Как справиться с аварией двигателя V8, когда процессу не хватает памяти
Оба узла консоли и Qt5 на основе V8 QJSEngine
может быть разбит следующим кодом:
a = []; for (;;) { a.push("hello"); }
вывод узла перед сбоем:
FATAL ERROR: JS Allocation failed - process out of memory
QJSEngine
Вывод перед сбоем:
#
# Fatal error in JS
# Allocation failed - process out of memory
#
Если я побегу QJSEngine
тестовое приложение (см. ниже) под отладчиком, оно показывает v8::internal::OS::DebugBreak
Звоните внутри кода V8. Если я заверну код вызова QJSEngine::evaluate
в __try-__except
( SEH), тогда приложение не будет аварийно завершено, но это решение зависит от Windows.
Вопрос: есть ли способ справиться v8::internal::OS::DebugBreak
независимым от платформы образом в приложениях узлов и Qt?
=== QJSEngine тестовый код ===
Среда разработки: QtCreator с Qt5 и Windows SDK 7.1, в Windows XP SP3
QJSEngineTest.pro:
TEMPLATE = app
QT -= gui
QT += core qml
CONFIG -= app_bundle
CONFIG += console
SOURCES += main.cpp
TARGET = QJSEngineTest
main.cpp без SEH (это приведет к сбою):
#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 с SEH (это не приводит к сбою, выводит "Фатальное исключение"):
#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;
}
1 ответ
Я не верю, что есть кроссплатформенный способ отловить фатальные ошибки V8, но даже если бы они были, или если бы был какой-то способ отловить их на всех платформах, которые вас волнуют, я не уверен, что это купит вас,
Проблема в том, что V8 использует глобальный флаг, который записывает, произошла ли фатальная ошибка. Как только этот флаг установлен, V8 будет отклонять любые попытки создания новых контекстов JavaScript, так что нет никакого смысла продолжать в любом случае. Попробуйте выполнить некий доброкачественный код JavaScript после обнаружения исходной фатальной ошибки. Если я прав, вы сразу же получите еще одну фатальную ошибку.
На мой взгляд, для Node и Qt правильнее было бы настроить V8, чтобы в первую очередь не вызывать фатальных ошибок. Теперь, когда V8 поддерживает изоляты и ограничения памяти, фатальные ошибки, убивающие процессы, больше не подходят. К сожалению, похоже, что код обработки ошибок V8 еще не полностью поддерживает эти новые функции, и все еще работает с допущением, что условия нехватки памяти всегда неисправимы.