我需要在特定的时间触发用户的回调函数,但是当触发回调函数时,对象已经被回收,无法使用。有什么方法可以保存对象而不被回收吗?回调触发后,我想手动回收内存
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
揭示了两个问题:
lpCB
是指向堆栈分配对象的指针,memcpy_s(..., &lpCB, ..)
您正在创建此指针的地址的副本。那是行不通的;首先因为lpCB
本身是非常短暂的,其次是因为堆栈分配的cb
它所指的(在函数callback
中)同样是短暂的。因此,只要callback
以这种方式创建的任何指针都将指向随机垃圾。函数返回。 (这部分问题是标准 C++,与 V8 或 Node 或 GC 或 Windows 或任何其他细节无关。)正如我在之前的回答中猜测的那样,您实际上是在尝试创建
Local
的长期副本。 。使用Persistent
来实现这一点。请阅读文档。
摘要:不要使用memcpy
上v8::Local
.
关于node.js - v8中如何防止对象被自动回收,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66187398/