What Are Unboxed Types?
In standard OCaml, most values are boxed - stored as pointers to heap-allocated memory. OxCaml introduces unboxed types that store values directly without indirection, enabling stack allocation and eliminating GC pressure.Boxed vs Unboxed
Boxed (Standard OCaml):Unboxed Types in httpz
httpz extensively uses three categories of unboxed types:1. Unboxed Primitives
int16# - 16-bit Unboxed Integer
Used for all buffer offsets, lengths, and positions since httpz’s max buffer is 32KB:int64# - 64-bit Unboxed Integer
Used for content lengths which can exceed 32-bit range:char# - Unboxed Character
Used throughout for character comparisons without boxing:2. Unboxed Records
Records defined with#{...} are allocated on the stack:
Parser State
Span Type
Request Type
.# syntax:
Header State
with syntax:
Chunk Type
Limits Configuration
3. Unboxed Tuples
Tuples with#(...) syntax are stack-allocated and commonly used for parser return values:
Returning span and position:
Local Allocations
OxCaml’s@ local mode annotation enables stack allocation of normally heap-allocated values:
Local Lists
Header lists are accumulated on the stack:exclave_ annotation indicates the function returns local values that must not escape to the heap.
Local Parameters
Functions can accept local parameters:local_ annotation on buf indicates it’s borrowed from the caller’s stack frame.
Performance Benefits
Memory Layout Comparison
Boxed Span (Standard OCaml):- Pointer to span: 1 word (8 bytes)
- Span header: 1 word (tag)
- Offset field: 1 word (boxed int) -> 2 words (pointer + value)
- Length field: 1 word (boxed int) -> 2 words (pointer + value)
- Total: 7 words (56 bytes) on heap
- Offset: 2 bytes (int16#)
- Length: 2 bytes (int16#)
- Total: 4 bytes on stack
Request Struct Comparison
Boxed (Standard OCaml):- ~20 words on heap for Request record
- ~10 words per header
- Header list pointers: ~2 words per cons cell
- Typical request: 50-100+ words on heap
- Request: ~10 words on stack
- Headers: ~8 words per header on stack
- Typical request: 0 words on heap, 80-160 words on stack
GC Impact
With boxed types:- Every request creates 50-100+ words of garbage
- At 1M req/s: 50-100 GB/s allocation rate
- Major GC collections every few seconds
- Unpredictable latency spikes
- 0 bytes allocated on heap
- No GC pressure from parsing
- Predictable, consistent latency
- Linear performance scaling
Best Practices
1. Use int16# for Small Values
When values fit in 16 bits, preferint16# over regular int:
2. Return Unboxed Tuples
When returning multiple values, use unboxed tuples:3. Thread Position Explicitly
Avoid mutable position by threading it through function returns:4. Use Spans Instead of Strings
Reference into buffers instead of copying:5. Mark Functions with exclave_
When returning local values, useexclave_: