node.js - v8中如何防止对象被自动回收

标签 node.js v8

我需要在特定的时间触发用户的回调函数,但是当触发回调函数时,对象已经被回收,无法使用。有什么方法可以保存对象而不被回收吗?回调触发后,我想手动回收内存

LPVOID createCallbackFunc(void *lpMethod, Local<Function> *lpCB, Local<Context> *lpContext)
{
  /*
t_cb - 55                    - push rbp
014F0001- 48 8B EC              - mov rbp,rsp
014F0004- 48 81 EC 90010000     - sub rsp,00000190

014F000B- 48 89 4C 24 08        - mov [rsp+08],rcx
014F0010- 48 89 54 24 10        - mov [rsp+10],rdx
014F0015- 4C 89 44 24 18        - mov [rsp+18],r8
014F001A- 4C 89 4C 24 20        - mov [rsp+20],r9

014F001F- 48 B9 0000000000000000 - mov rcx,0000000000000000
014F0029- 48 BA 0000000000000000 - mov rdx,0000000000000000
014F0033- 4C 8D 44 24 08        - lea r8,[rsp+08]
014F0038- 4C 8D 4D 10           - lea r9,[rbp+10]

014F003C- 48 B8 F0ACAB14FE7F0000 - mov rax,user32.MessageBoxA
014F0046- FF D0                 - call rax

014F0048- 48 81 C4 90010000     - add rsp,00000190
014F004F- 48 8B E5              - mov rsp,rbp
014F0052- 5D                    - pop rbp
014F0053- C3                    - ret

*/

  string code_str = "55 48 8B EC 48 81 EC 90 01 00 00 48 89 4C 24 08 48 89 54 24 10 4C 89 44 24 18 4C 89 4C 24 20 48 B9 00 00 00 00 00 00 00 00 48 BA 00 00 00 00 00 00 00 00 4C 8D 44 24 08 4C 8D 4D 10 48 B8 F0 AC AB 14 FE 7F 00 00 FF D0 48 81 C4 90 01 00 00 48 8B E5 5D C3";

  vector<BYTE> code_bytes = byteStr2Bytes(code_str);

  memcpy_s(code_bytes.data() + 0x21, sizeof(uintptr_t), &lpCB, sizeof(uintptr_t));
  memcpy_s(code_bytes.data() + 0x2B, sizeof(uintptr_t), &lpContext, sizeof(uintptr_t));
  memcpy_s(code_bytes.data() + 0x3E, sizeof(uintptr_t), &lpMethod, sizeof(uintptr_t));

  auto newmem = VirtualAlloc(0, code_bytes.size() + sizeof(uintptr_t), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
  memcpy_s(newmem, code_bytes.size(), code_bytes.data(), code_bytes.size());
  return newmem;
}

BOOL cb_test(Local<Function> &cb, Local<Context> &context, uintptr_t *a, uintptr_t *b)
{
  // Will not print, and will give an error
  if (cb->IsFunction())
  {
    printf("xxx\n");
  }
  return FALSE;
};

void callback(const FunctionCallbackInfo<Value> &args)
{
  Isolate *isolate = args.GetIsolate();
  auto context = isolate->GetCurrentContext();

  auto cb = args[0].As<Function>();
  LPVOID addr = createCallbackFunc(&cb_test, &cb, &context);

  args.GetReturnValue().Set(Number::New(isolate, (uintptr_t)addr));
}

我当前的环境是windows 10和nodejs 14.15.4

最佳答案

您的示例不完整(例如 createCallbackFunc 做什么?),因此很难确定发生了什么,但这里有一些需要考虑的一般要点:

  • 只要对象可访问,就不会被垃圾回收。这就是垃圾收集器的意义所在。
  • 您无法手动释放/回收由垃圾收集器管理的对象。
  • 我怀疑,就目前的情况而言,问题出在句柄上。一个Local<...>顾名思义,意味着在明确定义的本地范围内使用。它的生命周期与周围的生命周期相关 HandleScope 。如果createCallbackFunc试图把它藏在某个地方,那么预计Local很快就会失效(这并没有说明它最初指向的对象,也与垃圾收集器无关)。您可以在https://v8.dev/docs/embed了解有关句柄及其生命周期的更多信息。 .
  • 如果您想要的是带有回调的弱引用(当对象被垃圾收集时将被调用),请查看“弱持久化”。请注意,无法保证何时(或是否根本)调用此类回调(这只是“尽力而为”,但例如很可能会跳过关闭时),因此将它们用于关键资源管理是一个坏主意.

更新问题后编辑: 来源createCallbackFunc揭示了两个问题:

  1. lpCB是指向堆栈分配对象的指针, memcpy_s(..., &lpCB, ..)您正在创建此指针的地址的副本。那是行不通的;首先因为lpCB本身是非常短暂的,其次是因为堆栈分配的cb它所指的(在函数 callback 中)同样是短暂的。因此,只要callback以这种方式创建的任何指针都将指向随机垃圾。函数返回。 (这部分问题是标准 C++,与 V8 或 Node 或 GC 或 Windows 或任何其他细节无关。)

  2. 正如我在之前的回答中猜测的那样,您实际上是在尝试创建 Local 的长期副本。 。使用Persistent来实现这一点。请阅读文档。

摘要:不要使用memcpyv8::Local .

关于node.js - v8中如何防止对象被自动回收,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66187398/

相关文章:

javascript - 如何在 Chrome 中正确读取和修复 Web 应用程序的内存使用情况

javascript - Bootstrap 工具提示/弹出窗口未正确显示

node.js - 进程将二进制数据记录到日志文件

node.js - Nodejs 和批处理作业

javascript - 从 C++ 填充 Node v8 Float32Array

javascript - 跟踪 Web 应用程序中所有 Javascript 的执行

node.js - 创建 Express 服务时如何在 Node.js 中使用 `index.js`?

node.js - 在没有 bodyParser 的情况下从 AngularJS 请求 Node.js 中的数据

javascript - 使用 V8 的 Javascript 中的文件系统 I/O

javascript - Node JS/V8 解构错误?