跳转到主要内容
ArkFFI 在 TypeScript 层管理部分内存,但大多数情况下 C 库的内存由 C 库自身管理。理解各场景的内存归属,可以避免泄漏和野指针。

概览

场景谁分配谁释放安全使用方式
基本类型传参(int、double)值传递,无分配
字符串传参(FFIType.CStringNAPI 层NAPI 层(调用后立即释放)无需操心
字符串返回值(callStringC 库C 库只读,不释放
const char* 结构体字段C 库C 库fromPtr 读取指针值,不释放
结构体传参(StructSchema用户(create用户自行管理create 返回的 ArrayBuffer 用完后释放
结构体返回值(StructSchemaArkFFI(内部 ArrayBuffer)用户调用 releasePtr读取后调用 releasePtr,否则 Map 常驻
getSymbolPtr / ffi.ptr仅获取地址,无分配

基本类型传参

intdoublechar 等基本类型通过寄存器或栈传递,不涉及任何内存分配。直接传入即可。
lib.symbols.add(2.0, 3.0); // 无分配,值传递

字符串传参

当参数类型为 FFIType.CString 时,NAPI 层会用 napi_get_value_string_utf8 获取 C 字符串,在堆上分配 char*,调用 C 函数后立即 delete[]。用户无需管理。
lib.symbols.compute(0, 4.0, 'square');
// ↑ NAPI 内部:allocate char* → call → delete[]

字符串返回值

callString 返回 C 库内部持有的 const char*,arkffi 只读取其内容(napi_create_string_utf8),不分配也不释放。指针的生命周期由 C 库管理。 结构体 fromPtrconst char* 字段同样返回指针数值,该指针指向 C 库内存,不要通过 releasePtr 释放
let ptr = result.name; // const char* 指针,指向 C 库
let name = new CString(ptr).toString(); // 只读
// 不要 releasePtr(ptr) ← 非 ArkFFI 管理

结构体传参

通过 StructSchema.create() 创建的 ArrayBuffer 由用户分配,传递给 C 函数后由用户自行管理其生命周期。
let buf = Complex.create({ real: 1, imag: 2 });
lib.symbols.complex_add(buf, otherBuf);
// buf 由用户管理,用完后赋值 null 即可 GC

结构体返回值(releasePtr

dlopen / CFunctionreturnsStructSchema 时,ArkFFI 内部会:
  1. 调用 NAPI 获取 ArrayBuffer
  2. 通过 ffi.ptr 获取其数据指针
  3. ArrayBuffer 存入 g_structResults Map 防止 GC
  4. 返回指针给用户
用户通过 fromPtr 读取后,应调用 releasePtr 释放 Map 中的引用,使 ArrayBuffer 可被 GC。
import { releasePtr } from 'arkffi';

let ptr = lib.symbols.complex_add(a, b);   // ArkFFI 内部分配 buffer
let result = Complex.fromPtr(ptr);          // 读取数据
releasePtr(ptr);                            // 释放引用(允许 GC)

不调用 releasePtr 会怎样?

g_structResults Map 持续持有 ArrayBuffer 的引用,指针始终有效。Map 条目在调用 releasePtr 或程序退出前不会被 GC,但一般不构成问题(条目数等于 struct 返回调用次数)。

释放错误指针会怎样?

releasePtr(ptr) 在 Map 中按 key 查找。如果 ptr 不是由 ArkFFI struct 返回分配的指针(例如来自 C 库的 const char*),Map 找不到该 key,静默无操作,不会崩溃。

指针类型(ptr、callback)

FFIType.ptrFFIType.callback 传达的是地址值(number),不涉及内存分配。地址由 C 库管理或由 JSCallback 内部槽位管理。
let applyPtr = ffi.getSymbolPtr(handle, 'apply_callback');
// 只获取地址,无分配

JSCallback ptr 指向内部槽位或 trampoline JSCallback 自己管理
close() 时释放槽位

核心原则

ArkFFI 只管理自己分配的内存。C 库的内存由 C 库管理。
内存来源管理方
napi_get_value_string_utf8 副本ArkFFI(自动释放)
struct 返回值内部 ArrayBufferArkFFI(releasePtr 释放)
C 库返回的 const char*C 库
用户 StructSchema.create() 产物用户
dlopen 内部 handleArkFFI(close()dlclose