Native runtime

Why VexaScript uses Oilpan and mimalloc

The native VexaScript runtime uses Oilpan and mimalloc for different kinds of memory. Oilpan decides when VexaScript objects can be collected. mimalloc handles ordinary allocations made by C++ containers and runtime code.

Oilpan arrived with the first C++ backend in commit a380895e. mimalloc was added in commit db813e29 on July 22, 2026.

Oilpan manages VexaScript objects

VexaScript objects can form cycles. Reference counting cannot remove a cycle when the objects still point to each other but the program can no longer reach them.

Source concept Oilpan representation
Class instance cppgc::GarbageCollected<T>
Object field cppgc::Member<T>
Long-lived root cppgc::Persistent<T>
Managed allocation Runtime Oilpan allocation helper

Generated classes report their managed fields to Oilpan. The collector starts from known roots, follows those fields, and removes unreachable objects, including cycles.

The backend did not use std::shared_ptr for all objects because cycles would leak unless the compiler also selected weak references throughout the program.

Managed arrays

An array may be the only object that points to one of its elements. The collector must therefore trace object references stored in array slots.

The native runtime uses ArrayObject. Arrays of managed objects expose their elements to Oilpan. Raw buffers and primitive arrays do not trace every value. This keeps object references safe without adding garbage-collector work to plain byte data.

mimalloc handles ordinary C++ allocation

Many native allocations are outside the VexaScript object heap.

Memory Owner
VexaScript classes and managed arrays Oilpan
C++ vectors, maps, strings, and compiler data C++ and mimalloc
SDL objects and foreign buffers The external library contract

mimalloc cannot trace VexaScript objects. Oilpan does not replace every allocation made by the C++ standard library. Using both keeps these jobs separate.

Sanitizer builds do not use the mimalloc override. AddressSanitizer and UndefinedBehaviorSanitizer need to intercept allocations themselves.

Measured allocator result

The comparison linked the same generated -O1 compiler object once with the system allocator and once with mimalloc.

Allocator Self-host time
System allocator 4.08 s
mimalloc 3.4.3 3.28 s
Reduction 19.6%

This compiler workload creates many strings, maps, syntax objects, and output buffers. Programs that allocate less memory should not be expected to see the same improvement.

Packaging mimalloc

The full mimalloc archive was about 1.3 MB. A smaller archive reduced it to about 248 KB. The first small archive kept only src/ and include/, but the build failed because CMake also needed project metadata and helper files.

The final archive keeps the source, headers, licenses, top-level CMake files, and the required CMake helpers. The native build caches the extracted files and compiled allocator.

The memory rule is simple: Oilpan tracks VexaScript objects, mimalloc services ordinary native allocation, and external APIs define the lifetime of their own resources. Managed pointers sent to workers or FFI code must still be rooted or copied safely.