当进程内存不足时如何处理 V8 引擎崩溃 [英] How to handle V8 engine crash when process runs out of memory

查看:137
本文介绍了当进程内存不足时如何处理 V8 引擎崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

node 控制台和 Qt5 基于 V8 的 QJSEngine 可以通过以下代码崩溃:

a = [];for (;;) { a.push("你好");}

节点崩溃前的输出:

致命错误:JS 分配失败 - 进程内存不足

QJSEngine 崩溃前的输出:

<预><代码>## JS 中的致命错误# 分配失败 - 进程内存不足#

如果我在调试器下运行我的 QJSEngine 测试应用程序(见下文),它会显示一个 v8::internal::OS::DebugBreak 在 V8 代码中调用.如果我将调用 QJSEngine::evaluate 的代码包装到 __try-__except (SEH),则应用不会崩溃,但此解决方案特定于 Windows.

问题:有没有办法在 node 和 Qt 应用程序中以独立于平台的方式处理 v8::internal::OS::DebugBreak?

=== QJSEngine 测试代码 ===

开发环境:QtCreator with Qt5 and Windows SDK 7.1, on Windows XP SP3

QJSEngineTest.pro:

TEMPLATE = appQT -= guiQT += 核心 qml配置 -= app_bundle配置 += 控制台源 += main.cpp目标 = QJSEngineTest

没有 SEH 的 main.cpp(这会崩溃):

#include int main(int, char**){尝试 {QJS引擎引擎;QJSValue value = engine.evaluate("a = []; for (;;) { a.push('hello'); }");qDebug(value.isError() ? "Error" : value.toString().toStdString().c_str());} 抓住 (...) {qDebug("异常");}返回0;}

带有 SEH 的 main.cpp(这不会崩溃,输出致命异常"):

#include #include 无效运行测试(){尝试 {QJS引擎引擎;QJSValue value = engine.evaluate("a = []; for (;;) { a.push('hello'); }");qDebug(value.isError() ? "Error" : value.toString().toStdString().c_str());} 抓住 (...) {qDebug("异常");}}int main(int, char**){__尝试 {运行测试();} __except(EXCEPTION_EXECUTE_HANDLER) {qDebug("致命异常");}返回0;}

解决方案

我不相信有一种跨平台的方法来捕获 V8 致命错误,但即使有,或者有什么方法可以捕获它们您关心的所有平台,我不确定这会给您带来什么.

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

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

Both node console and Qt5's V8-based QJSEngine can be crashed by the following code:

a = []; for (;;) { a.push("hello"); }

node's output before crash:

FATAL ERROR: JS Allocation failed - process out of memory

QJSEngine's output before crash:

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

If I run my QJSEngine test app (see below) under a debugger, it shows a v8::internal::OS::DebugBreak call inside V8 code. If I wrap the code calling QJSEngine::evaluate into __try-__except (SEH), then the app won't crash, but this solution is Windows-specific.

Question: Is there a way to handle v8::internal::OS::DebugBreak in a platform-independent way in node and Qt applications?

=== QJSEngine test code ===

Development environment: QtCreator with Qt5 and Windows SDK 7.1, on Windows XP SP3

QJSEngineTest.pro:

TEMPLATE = app
QT -= gui
QT += core qml
CONFIG -= app_bundle
CONFIG += console
SOURCES += main.cpp
TARGET = QJSEngineTest

main.cpp without SEH (this will crash):

#include <QtQml/QJSEngine>

int main(int, char**)
{
  try {
    QJSEngine engine;
    QJSValue value = engine.evaluate("a = []; for (;;) { a.push('hello'); }");
    qDebug(value.isError() ? "Error" : value.toString().toStdString().c_str());
  } catch (...) {
    qDebug("Exception");
  }
  return 0;
}

main.cpp with SEH (this won't crash, outputs "Fatal exception"):

#include <QtQml/QJSEngine>
#include <Windows.h>

void runTest()
{
  try {
    QJSEngine engine;
    QJSValue value = engine.evaluate("a = []; for (;;) { a.push('hello'); }");
    qDebug(value.isError() ? "Error" : value.toString().toStdString().c_str());
  } catch (...) {
    qDebug("Exception");
  }
}

int main(int, char**)
{
  __try {
    runTest();
  } __except(EXCEPTION_EXECUTE_HANDLER) {
    qDebug("Fatal exception");
  }
  return 0;
}

解决方案

I don't believe there's a cross-platform way to trap V8 fatal errors, but even if there were, or if there were some way to trap them on all the platforms you care about, I'm not sure what that would buy you.

The problem is that V8 uses a global flag that records whether a fatal error has occurred. Once that flag is set, V8 will reject any attempt to create new JavaScript contexts, so there's no point in continuing anyway. Try executing some benign JavaScript code after catching the initial fatal error. If I'm right, you'll get another fatal error right away.

In my opinion the right thing would be for Node and Qt to configure V8 to not raise fatal errors in the first place. Now that V8 supports isolates and memory constraints, process-killing fatal errors are no longer appropriate. Unfortunately it looks like V8's error handling code does not yet fully support those newer features, and still operates with the assumption that out-of-memory conditions are always unrecoverable.

这篇关于当进程内存不足时如何处理 V8 引擎崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆