如何判断v8隔离实例使用了太多内存
How to tell that a v8 isolate instance uses too much memory?
我使用谷歌的v8引擎在我的应用程序中嵌入javascript。在某些时候,我将调用用户提供的代码,并且我希望确保它不会因分配过多内存而表现不佳。目前,当javascript试图创建或调整数组的大小时,例如,我得到一个不礼貌的消息:
#
# Fatal error in CALL_AND_RETRY_LAST
# Allocation failed - process out of memory
#
然后整个进程崩溃并产生SIGILL。显然,这是不可接受的。我需要能够运行用户提供的代码,但是…在引擎执行所有代码之前,手动审查所有代码是不可行的。
在这种情况下,我最理想的做法是终止消耗过多内存的隔离(不影响可能正在运行的任何其他隔离)。是否有任何方法可以指定js程序在失败之前允许使用的最大内存量,因此,如果超过该限制,而不是使进程崩溃,调用Run或Call命令将简单地返回一个错误或设置一些状态标志,表明它异常终止。
我已经尝试过的事情:
在隔离创建时设置自定义array_buffer分配器,它跟踪使用了多少内存,并在内存使用量过高时终止隔离>我的分配器的Allocate函数从未被调用过。
调用AddMemoryAllocationCallback函数,该函数跟踪内存使用情况,并在分配超过一定数量时尝试通过TerminateExecution()终止隔离。这个函数确实被调用,但是在这个函数只报告了几兆字节的使用之后,我得到了内存不足的错误,而我知道一个事实,即由行为不良的v8函数创建的数据是FAR大于此。
通过SetFatalErrorHandler设置一个致命错误处理程序,并试图在那里调用TerminateExecution。这个函数会被调用,但是它不能防止进程崩溃。
还有什么我可以试试的吗?
编辑:V8团队的权威回应——你不能。但是他们会接受一个补丁。
v8::Isolate::SetFatalErrorHandler()应该允许你不崩溃。但是,我的理解是,隔离事件发生后仍然无法使用。可能没有办法绕过它,因为隔离将处于不可恢复的状态。
http://v8.paulfryzel.com/docs/master/classv8_1_1_isolate.html a131f1e2e6a80618ac3c8c266a041851d
(也许吧。在2013-2014年的时间框架内,似乎有很多关于这个的事情,谷歌的人说,正确的做法是让v8杀死这个过程——很多人认为这是愚蠢的。我没有看到任何分辨率)
edit:邮件列表的回复是你不能这样做。如果不影响性能,他们会接受一个补丁。
编辑:这只是另一个线程,有人发布了一个似乎是在非恶意情况下避免OOM的好方法:
https://groups.google.com/forum/!主题/v8用户/vKn1hVs8KNQ
我将堆限制设置为实际所需限制的8倍。然后,每次之后调用到隔离,我检查内存使用是否超过了为了限制。如果是,我调用垃圾收集。如果仍然在此之后超过限制,那么我在该点终止隔离。
同时,我们还强制50ms的CPU时间限制。在实践中,分配大量内存的脚本往往会耗尽CPU时间在它达到8倍堆限制之前(特别是当GC减慢速度时)
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 常量类实例的C++内存地址
- 是否应该使用继承来减少内存消耗的实例的内存分配?
- 在C++中,为什么仅包含与其基类实例的联合的派生类占用的内存多于联合的大小?
- 在函数中实例化的 STL 对象正在占用堆栈或堆上的内存?
- 将内存文件添加到 clang 编译器实例
- 在结构中使用位字段并使用C++从内存中读取实例
- 如何将内存分配给具有数组成员的类的实例
- std::array 模板实例会占用更多的代码内存吗?
- 插入std :: basic_ostream实例化输出时的内存故障
- 构造函数C++中的类实例内存地址
- 基本指针如何能够在派生的类实例中了解基本成员的内存位置
- 有没有办法区分对象实例使用的内存类型
- 如果我声明一个没有名称的类实例,它会保留在内存中吗?
- 当我创建一个int指针并实例化一个数组时,数组在内存中发生了什么
- 派生类的实例化是否为基类的私有成员分配内存
- 分配给 cpp 中定义的全局静态变量的内存是否在 C++ 中删除其类的实例后释放
- 从用户控制的内存池中分配和实例化对象
- C++中参数列表中实例化对象的内存管理
- 重载运算符 std::ostream& 运算符<<打印实例内存地址