Skip to content

Instantly share code, notes, and snippets.

@kevmoo
Created April 12, 2026 05:39
Show Gist options
  • Select an option

  • Save kevmoo/eb18176e0662c7c66d0995599679b274 to your computer and use it in GitHub Desktop.

Select an option

Save kevmoo/eb18176e0662c7c66d0995599679b274 to your computer and use it in GitHub Desktop.
SDK Isolate as of Dart 3.10

Isolate groups in Dart (introduced in version 2.15) allow isolates to share code and some memory structures, significantly increasing the efficiency of communication. Based on my investigation of the Dart SDK's runtime implementation and documentation, here is a summary of what is efficient to send:

1. Objects Shared by Reference ($O(1)$ cost)

When isolates are in the same isolate group (which is the default for isolates created via Isolate.spawn()), the following objects are shared by reference rather than copied:

  • All Strings: In the Dart VM, all strings are considered "deeply immutable" and are shared by reference.
  • Primitive Types: bool, int, double, and Null.
  • Constants: Any object created with the const keyword.
  • Special System Objects: SendPort, Capability, RegExp, StackTrace, and Type.
  • Deeply Immutable Instances: Objects of classes annotated with @pragma('vm:deeply-immutable').
  • Stateless Closures: Closures that do not capture any mutable state from their environment.
  • Unmodifiable Typed Data: If a TypedData (like Uint8List) is created as unmodifiable (e.g., via Uint8List.unmodifiable()), it can be shared by reference if its backing store is also marked immutable.

2. Objects Transferred or Moved ($O(1)$ cost)

  • TransferableTypedData: This is a specific wrapper for typed data that moves ownership. When you send it, the underlying memory is moved to the receiving isolate, and the sender can no longer access it.
  • Isolate.exit(port, message): This is a very efficient way to return a result. If you call Isolate.exit, the message object graph is "reassigned" to the receiving isolate without copying (if they are in the same group), effectively making it a constant-time operation for even huge data structures.

3. Objects Copied in the Same Heap ($O(n)$ but fast)

For most other mutable objects (like normal List, Map, or user-defined class instances) sent within the same isolate group:

  • The VM performs a "fast copy" by traversing the object graph and allocating new objects directly in the shared heap.
  • This is significantly faster than the old "slow copy" (which involved serializing to a byte buffer and deserializing), but it still scales with the size of the object graph.

4. Objects Sent Across Isolate Groups ($O(n)$ and slow)

If you use Isolate.spawnUri(), the new isolate is in a separate isolate group. Communication between different groups always requires full serialization and deserialization (O(N) and much slower).

Recommendations for Efficiency:

  • Prefer const: Use constants whenever possible to ensure $O(1)$ sharing.
  • Use Isolate.exit: When an isolate is finished with its work, use Isolate.exit(resultPort, data) to send back large results for free.
  • Use TransferableTypedData: For large buffers that don't need to be shared, transferring ownership is the most efficient $O(1)$ path.
  • Use @pragma('vm:deeply-immutable'): If you have custom data models that are immutable, this pragma allows the VM to share them by reference.

You can find more technical details in the following files within the repo:

  • runtime/docs/deeply_immutable.md: Explains how the VM identifies and handles immutable types.
  • runtime/vm/object_graph_copy.cc: The C++ implementation of the fast object copier used within isolate groups.
  • sdk/lib/isolate/isolate.dart: Documentation for SendPort.send and Isolate.exit.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment