使用 node-ffi-napi总是调用函数会泄漏内存

问题描述

(原来涉及 CGO 的问题被删除,取而代之的是一个更简单的演示,展示了我认为的核心问题,旧问题仍然可以在编辑历史中访问。)

用例:我正在使用 npm 包 ffi-napi调用本机函数(没什么奇怪的)。

问题:每次调用,甚至是 void() 函数,都会泄漏内存,这似乎有点问题。

我想出的最简单的重现:

const lib = ffi.Library(null,{
    'atoi': ['int',['string']]
});

let i = 0;
while (++i) {
    lib.atoi('1234');

    global.gc();

    if (i % 100000 == 0) {
        console.log(`iter. #${i} RSS MBs used: ${process.memoryUsage().RSS / 1024 / 1024}`);
    }
}

输出

iter. #100000 RSS MBs used: 304.8359375
iter. #200000 RSS MBs used: 509.48828125
iter. #300000 RSS MBs used: 755.44140625
iter. #400000 RSS MBs used: 905.8203125
iter. #500000 RSS MBs used: 1123.90234375
iter. #600000 RSS MBs used: 1370.88671875
iter. #700000 RSS MBs used: 1612.45703125
-- CUT --
iter. #6200000 RSS MBs used: 11568.64453125
iter. #6300000 RSS MBs used: 11794.2109375
iter. #6400000 RSS MBs used: 11905.625
iter. #6500000 RSS MBs used: 12026.44921875

<--- Last few GCs --->

[1217086:0x5627be68a030]   168590 ms: Mark-sweep 2003.3 (2070.7) -> 1992.3 (2072.7) MB,3546.0 / 170.8 ms  (average mu = 0.101,current mu = 0.024) allocation failure scavenge might not succeed
[1217086:0x5627be68a030]   171579 ms: Mark-sweep 2005.6 (2072.7) -> 1994.6 (2074.7) MB,2907.8 / 231.8 ms  (average mu = 0.068,current mu = 0.027) allocation failure scavenge might not succeed


<--- JS stacktrace --->

==== JS stack trace =========================================

    0: ExitFrame [pc: 0x7fe054be1679]
Security context: 0x146fda0db989 <JSObject>
    1: debug [0x11881d6991b9] [/home/morgan/Documents/Code/nogame/node_modules/debug/src/common.js:~64] [pc=0x553685c70a5](this=0x036c76042a69 <JSGlobal Object>)
    2: arguments adaptor frame: 1->0
    3: ./apps/server/src/main.ts [0x1cd68b8fffa9] [/home/morgan/Documents/Code/nogame/dist/apps/server/main.js:~94] [pc=0x553685d6a90](this=0x23bff30191f9 <Objec...

Fatal error: Ineffective mark-compacts near heap limit Allocation Failed - JavaScript heap out of memory
 1: 0x7fe053f2da9c node::Abort() [/lib/x86_64-linux-gnu/libnode.so.72]
 2: 0x7fe053e61872  [/lib/x86_64-linux-gnu/libnode.so.72]
 3: 0x7fe054107aea v8::Utils::ReportOOMFailure(v8::internal::Isolate*,char const*,bool) [/lib/x86_64-linux-gnu/libnode.so.72]
 4: 0x7fe054107dcb v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*,bool) [/lib/x86_64-linux-gnu/libnode.so.72]
 5: 0x7fe0542b59b9  [/lib/x86_64-linux-gnu/libnode.so.72]
 6: 0x7fe0542c5da7 v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector,v8::GCCallbackFlags) [/lib/x86_64-linux-gnu/libnode.so.72]
 7: 0x7fe0542c6a8f v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace,v8::internal::GarbageCollectionReason,v8::GCCallbackFlags) [/lib/x86_64-linux-gnu/libnode.so.72]
 8: 0x7fe0542c8d7c v8::internal::Heap::AllocaterawWithLightRetry(int,v8::internal::AllocationType,v8::internal::Allocationorigin,v8::internal::AllocationAlignment) [/lib/x86_64-linux-gnu/libnode.so.72]
 9: 0x7fe0542c8de8 v8::internal::Heap::AllocaterawWithRetryOrFail(int,v8::internal::AllocationAlignment) [/lib/x86_64-linux-gnu/libnode.so.72]
10: 0x7fe05428d7ef v8::internal::Factory::NewFillerObject(int,bool,v8::internal::Allocationorigin) [/lib/x86_64-linux-gnu/libnode.so.72]
11: 0x7fe0545df559 v8::internal::Runtime_AllocateInYoungGeneration(int,unsigned long*,v8::internal::Isolate*) [/lib/x86_64-linux-gnu/libnode.so.72]
12: 0x7fe054be1679  [/lib/x86_64-linux-gnu/libnode.so.72]
[1]    1217086 IOT instruction  node --expose-gc dist/apps/server/main.js

注意:ffi-cross 也会出现同样的问题。

Valgrind 在此处记录 5000 次迭代:https://pastebin.com/p3Uv4WwR

泄漏堆栈清晰可见:

==1223109== 400,160 bytes in 5,002 blocks are definitely lost in loss record 61 of 61
==1223109==    at 0x4A3F723: operator new(unsigned long) (vg_replace_malloc.c:417)
==1223109==    by 0x5428CE9: napi_create_reference (in /usr/lib/x86_64-linux-gnu/libnode.so.72)
==1223109==    by 0xDACDEFF: (anonymous namespace)::InstanceData::GetBufferData(napi_value__*) (in /home/morgan/Documents/Code/redacted/node_modules/ref-napi/prebuilds/linux-x64/node.napi.node)
==1223109==    by 0xDCE372F: FFI::FFI::FFICall(Napi::CallbackInfo const&) (in /home/morgan/Documents/Code/redacted/node_modules/ffi-napi/build/Release/ffi_bindings.node)
==1223109==    by 0xDCE6B0D: Napi::details::CallbackData<void (*)(Napi::CallbackInfo const&),void>::Wrapper(napi_env__*,napi_callback_info__*) (in /home/morgan/Documents/Code/redacted/node_modules/ffi-napi/build/Release/ffi_bindings.node)
==1223109==    by 0x5421127: ??? (in /usr/lib/x86_64-linux-gnu/libnode.so.72)
==1223109==    by 0x56AFB48: v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHandlerInfo) (in /usr/lib/x86_64-linux-gnu/libnode.so.72)
==1223109==    by 0x56AFEF4: ??? (in /usr/lib/x86_64-linux-gnu/libnode.so.72)
==1223109==    by 0x56B0749: ??? (in /usr/lib/x86_64-linux-gnu/libnode.so.72)
==1223109==    by 0x56B101C: v8::internal::Builtin_HandleApiCall(int,v8::internal::Isolate*) (in /usr/lib/x86_64-linux-gnu/libnode.so.72)
==1223109==    by 0x6123778: ??? (in /usr/lib/x86_64-linux-gnu/libnode.so.72)
==1223109==    by 0x60A8F03: ??? (in /usr/lib/x86_64-linux-gnu/libnode.so.72)

我将在图书馆的 GitHub 上发布一个问题,但任何帮助将不胜感激。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)