Node.js 进程内存不足时如何处理V8引擎崩溃

Node.js 进程内存不足时如何处理V8引擎崩溃,node.js,v8,qt5,seh,debugbreak,Node.js,V8,Qt5,Seh,Debugbreak,控制台和Qt5基于V8的系统都可能因以下代码而崩溃: a = []; for (;;) { a.push("hello"); } 崩溃前节点的输出: FATAL ERROR: JS Allocation failed - process out of memory # # Fatal error in JS # Allocation failed - process out of memory # QJSEngine崩溃前的输出: FATAL ERROR: JS Allocation fa

控制台和Qt5基于V8的系统都可能因以下代码而崩溃:

a = []; for (;;) { a.push("hello"); }
崩溃前节点的输出:

FATAL ERROR: JS Allocation failed - process out of memory
#
# Fatal error in JS
# Allocation failed - process out of memory
#
QJSEngine
崩溃前的输出:

FATAL ERROR: JS Allocation failed - process out of memory
#
# Fatal error in JS
# Allocation failed - process out of memory
#
如果我在调试器下运行我的
QJSEngine
测试应用程序(见下文),它将显示V8代码中的调用。如果我将调用
QJSEngine::evaluate
的代码包装到
\uuu try-\uu中,则应用程序不会崩溃,但此解决方案是特定于Windows的

问题:在节点和Qt应用程序中,是否有一种方法可以以独立于平台的方式处理
v8::internal::OS::DebugBreak

==QJSEngine测试代码===

开发环境:在Windows XP SP3上使用Qt5和Windows SDK 7.1的QtCreator

QJSEngineTest.pro:

TEMPLATE = app
QT -= gui
QT += core qml
CONFIG -= app_bundle
CONFIG += console
SOURCES += main.cpp
TARGET = QJSEngineTest
main.cpp不带SEH(这将崩溃):

#包括
int main(int,char**)
{
试一试{
QJS发动机;
QJSValue=engine.evaluate(;;){a.push('hello');})中的(“a=[];for(;;);
qDebug(value.isError()?“Error”:value.toString().tostString().c_str());
}捕获(…){
qDebug(“例外”);
}
返回0;
}
带SEH的main.cpp(不会崩溃,输出“致命异常”):

#包括
#包括
void runTest()
{
试一试{
QJS发动机;
QJSValue=engine.evaluate(;;){a.push('hello');})中的(“a=[];for(;;);
qDebug(value.isError()?“Error”:value.toString().tostString().c_str());
}捕获(…){
qDebug(“例外”);
}
}
int main(int,char**)
{
__试一试{
runTest();
}_uuu除外(异常执行处理程序){
qDebug(“致命异常”);
}
返回0;
}

我不相信有跨平台的方法来捕获V8致命错误,但即使有,或者如果有某种方法可以捕获您关心的所有平台上的错误,我也不确定这会给您带来什么好处

问题是V8使用了一个记录是否发生致命错误的。一旦设置了该标志,V8将拒绝任何创建新JavaScript上下文的尝试,因此继续下去没有意义。在捕捉到最初的致命错误后,尝试执行一些良性JavaScript代码。如果我是对的,你马上就会犯另一个致命的错误


在我看来,正确的做法是Node和Qt首先将V8配置为不引发致命错误。既然V8支持隔离和内存约束,进程终止致命错误就不再合适了。不幸的是,V8的错误处理代码似乎还不完全支持这些新功能,并且仍然假设内存不足的情况始终不可恢复。

还请注意,您可以在中止之前使用V8::SetFatalErrorHandler()注册回调,尽管这仍然不能让您解开v8堆栈。您还可以使用--no-hard_Abort()控制OS::Abort(),使进程安静地退出(SIGABRT),而不是访问冲突(V8_IMMEDIATE_CRASH())。(我不确定在哪种情况下调用DebugBreak()——可能只有在附加了调试器时才调用。)