Memory Model
MetaScript uses ORC (Optimized Reference Counting) for the C backend, providing deterministic memory management without garbage collection pauses.
Why ORC?
Traditional garbage collectors have unpredictable pauses. Reference counting is predictable but slow. ORC combines the best of both:
| Approach | Predictable | Fast | No Pauses |
|---|---|---|---|
| Tracing GC | - | Yes | - |
| Naive RC | Yes | - | Yes |
| ORC | Yes | Yes | Yes |
ORC achieves ~~5% overhead compared to manual memory management, while being completely automatic.
How ORC Works
Basic Reference Counting
Every object tracks how many references point to it:
const user = new User("Alice") // refcount = 1
const copy = user // refcount = 2
// copy goes out of scope // refcount = 1
// user goes out of scope // refcount = 0, freedCycle Detection
ORC handles cycles that break naive reference counting:
class Node {
next: Node | null = null
}
const a = new Node()
const b = new Node()
a.next = b
b.next = a // Cycle! Naive RC would leak
// ORC detects and collects cycles automaticallyMove Semantics
When possible, DRC moves values instead of copying (last-read analysis). You can also use the move keyword to explicitly transfer ownership — the source is zeroed, no copy:
// Implicit move — analyzer detects last use, no copy
function processUser(user: User): void {
console.log(user.name)
}
const user = new User("Alice")
processUser(user) // last use — moved automatically
// Explicit move — not required, for advanced performance optimization only
// Transfer ownership, source is zeroed
const y = move x; // y owns the data, x is zeroed
return move data; // caller takes ownership, local zeroed
consume(move buffer); // callee takes ownership
// Useful with actors — zero-copy message passing
let state: MutableState = { count: 0 };
worker.process(move state); // zero-copy, state invalidated
// state.count; // COMPILE ERROR: used after moveMemory Zones
For performance-critical code, use memory zones:
import { Zone } from "@metascript/core"
Zone.scoped((zone) => {
// All allocations use the zone
const users = zone.alloc(User, 1000)
for (const user of users) {
process(user)
}
// Everything freed at once when zone exits
})Next Steps
- Learn about Compile Targets to understand deployment options
- Explore Compile-Time Power for zero-cost abstractions
- Read the Performance Guide for optimization tips