如何判断 v8 isolate 实例使用了太多内存?

How to tell that a v8 isolate instance uses too much memory?

我正在使用 Google 的 v8 引擎在我的应用程序中嵌入 javascript。在某些时候,我会调用用户提供的代码,我想确保它不会因为分配太多内存而表现不佳。当前,例如,当 javascript 试图使数组过大或将其调整为过大时,我会收到一条粗鲁的消息:

#
# Fatal error in CALL_AND_RETRY_LAST
# Allocation failed - process out of memory
#

然后整个进程因 SIGILL 而崩溃。显然,这是不能接受的。我需要 运行 用户提供的代码的能力,但是......在引擎执行之前手动审查所有代码是不可行的。

在这种情况下,我最理想的做法是简单地终止消耗过多内存的 isolate(而不影响可能 运行ning 的任何其他 isolate)。有什么方法可以指定 js 程序在失败之前允许使用的最大内存量,因此如果它超过该限制,而不是使进程崩溃,调用 运行 或 Call 命令会只是 return 一个错误或设置一些状态标志表明它被异常终止。

到目前为止我尝试过的事情:

在创建 isolate 时设置自定义 array_buffer 分配器,它跟踪正在使用的内存量并在内存使用率过高时终止 isolate> 我的分配器的 Allocate 函数从未得到打电话。

使用跟踪内存使用情况的函数调用 AddMemoryAllocationCallback,并在分配超过一定数量时尝试通过 TerminateExecution() 终止隔离。这个函数确实被调用了,但是在这个函数只报告了几兆字节被使用后我得到了一个内存不足的错误,而我知道一个事实是由行为不佳的 v8 函数创建的数据是 FAR 比那个大。

通过 SetFatalErrorHandler 设置致命错误处理程序并尝试在那里调用 TerminateExecution。此函数确实会被调用,但它不会阻止进程崩溃。

还有什么我可以尝试的吗?

编辑:V8 团队的权威回应——你不能。但他们会接受补丁。

v8::Isolate::SetFatalErrorHandler() 应该不会崩溃。但是,我的理解是隔离在事后仍然无法使用。可能没有办法解决这个问题,因为 isolate 将处于无法恢复的状态。

http://v8.paulfryzel.com/docs/master/classv8_1_1_isolate.html#a131f1e2e6a80618ac3c8c266a041851d

(也许吧。在 2013-2014 年的时间框架内似乎有很多关于此的事情发生,google 的人说正确的做法是让 v8 终止进程——很多人认为这是愚蠢的。我没有看到任何解决方案)

编辑:邮件列表回复说你不能这样做。如果补丁没有性能影响,他们将接受补丁。

编辑:关于这个只有另一个线程,有人发布了似乎是在非恶意情况下避免 OOM 的好方法:

https://groups.google.com/forum/#!topic/v8-users/vKn1hVs8KNQ

I set the heap limit to 8x the limit I actually want. Then, after each call into the isolate, I check if the memory usage has gone over the intended limit. If so, I invoke garbage collection. If it's still over the limit after that, then I terminate the isolate at that point.

Meanwhile, we also enforce a CPU time limit of 50ms. In practice, a script that allocates tons of memory tends to run out of CPU time before it can hit the 8x heap limit (especially as the GC slows things down when approaching the limit).