Overview
| Scenario | Allocator | Deallocator | Safe Usage |
|---|---|---|---|
| Primitive args (int, double) | — | — | Pass by value, no allocation |
String args (FFIType.CString) | NAPI layer | NAPI layer (freed after call) | No action needed |
String return value (callString) | C library | C library | Read only, do not free |
const char* struct field | C library | C library | fromPtr reads pointer, do not free |
Struct arg (StructSchema) | User (create) | User | Free ArrayBuffer when done |
Struct return (StructSchema) | ArkFFI (internal ArrayBuffer) | User calls releasePtr | Call releasePtr after reading |
getSymbolPtr / ffi.ptr | — | — | Address only, no allocation |
Primitive Args
int, double, char, etc. are passed by value via registers or stack — no allocation involved.
String Args
When a parameter type isFFIType.CString, the NAPI bridge calls napi_get_value_string_utf8 to get the C string, allocates a char* on the heap, calls the C function, and immediately delete[] it. No user action needed.
String Return Values
callString returns a const char* owned by the C library. ArkFFI only reads its content via napi_create_string_utf8 — it does not allocate or free. The pointer lifecycle is managed by the C library.
Similarly, const char* fields from fromPtr return a pointer value pointing into C library memory. Do not pass it to releasePtr.
Struct Args
ArrayBuffer created by StructSchema.create() is allocated by the user. After passing it to a C function, the user owns its lifecycle.
Struct Returns (releasePtr)
When dlopen / CFunction has a StructSchema as returns, ArkFFI:
- Calls NAPI to obtain an
ArrayBuffer - Gets its data pointer via
ffi.ptr - Stores the
ArrayBufferin an internalMapto prevent GC - Returns the pointer to the user
fromPtr, call releasePtr to remove the Map reference and allow GC.
What if I forget to call releasePtr?
The internalMap holds the ArrayBuffer reference indefinitely. The pointer remains valid. The entry is only removed by releasePtr or program exit. This is generally harmless — entries grow linearly with struct return calls.
What if I pass the wrong pointer to releasePtr?
releasePtr(ptr) does a Map lookup by key. If ptr was not allocated by an ArkFFI struct return (e.g., a C library const char*), the key is not found and the call is silently ignored — no crash.
Pointer Types (ptr, callback)
FFIType.ptr and FFIType.callback pass address values (number) — no allocation. The address is managed by the C library or by JSCallback’s internal slot system.
Core Principle
ArkFFI only manages memory it allocates. C library memory is managed by the C library.
| Memory Source | Manager |
|---|---|
napi_get_value_string_utf8 copy | ArkFFI (auto free) |
Struct return internal ArrayBuffer | ArkFFI (releasePtr to free) |
C library const char* | C library |
User StructSchema.create() result | User |
dlopen internal handle | ArkFFI (close() calls dlclose) |