Webinar, Lecture
How OCaml Represents Values in Memory
Subject Matter
- OCaml's type system distinguishes between "immediate" types and "boxed" types, a distinction critical for memory layout and garbage collection efficiency.
- Immediate types (e.g.,
unit,bool,char,int) are represented directly as 63-bit tagged integers. - Boxed types (e.g., arrays, tuples, records) require heap allocation and are represented as pointers to blocks containing a header and payload.
Immediate Type Representations
unitis represented as integer0.falseis represented as integer0.trueis represented as integer1.charvalues are encoded as their ASCII byte values.intvalues are stored as themselves, offset to accommodate the tagging scheme.
Garbage Collection Mechanics
- Tagged Integers: All heap-allocated blocks are 8-byte word-aligned, ensuring the lower three bits are always
0. - The garbage collector uses the least significant bit (LSB) to distinguish types:
- LSB
1indicates a tagged integer. - LSB
0indicates a pointer to a heap block.
- LSB
- This tagging scheme reduces integer precision to 63 bits but simplifies runtime type checks.
- Block Headers: Every allocated block includes a 1-word header preceding the data.
- The header contains a 54-bit size field (capable of addressing ~16 petabytes).
- The header contains 2 bits used internally by the garbage collector for marking/coloring.
- The header contains a 1-byte tag used to identify specific block types and behavior.
- Tagged Integers: All heap-allocated blocks are 8-byte word-aligned, ensuring the lower three bits are always
Special Boxed Types and Tags
- Floats (Double):
- 64-bit IEEE doubles cannot use LSB tagging; thus, they are boxed as one-word blocks.
- Blocks containing floats use tag
253(the "double tag"). - The garbage collector recognizes tags $\ge$ 251 as non-scannable to avoid dereferencing internal data as pointers.
- Strings:
- Strings are tightly packed byte arrays where arbitrary words might not satisfy alignment or tagging rules.
- String blocks use tag
252. - The GC treats any tag $\ge$ 251 as containing no scannable pointer data.
- Floats (Double):
Variant Type Encoding
- Variant constructors are divided into two families: immediate (no payload) and non-immediate (with payload).
- Immediate Constructors (e.g.,
A,C):- Represented directly as integers based on their definition order.
- Example:
Ais0,Cis1.
- Non-Immediate Constructors (e.g.,
B,D):- Represented as boxed blocks where the constructor identifier is stored in the block's tag field.
- Tags start from
0for the first non-immediate constructor defined. - There is a maximum limit of approximately 250 non-immediate constructors per variant due to the single-byte tag constraint.
Runtime Capabilities and Future Work
- The runtime can dynamically inspect any value to determine if it is an integer or a pointer and, if the latter, retrieve the exact heap block size via the header.
- The current implementation ensures a simple runtime and efficient garbage collection by strictly defining memory layouts.
- Forward-looking statement: Future development will focus on integrating traditional value types with "unboxed" types to further optimize performance.