2013-05-28 37 views
8

兩個node控制檯和處理V8引擎崩潰QT5的V8型QJSEngine可以通過下面的代碼崩潰:如何在流程運行的內存

FATAL ERROR: JS Allocation failed - process out of memory 

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

節點的輸出墜毀前飛機墜毀前

QJSEngine的輸出:

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

如果我在調試器下運行我的QJSEngine測試應用程序(請參閱下文),它顯示V8代碼中的v8::internal::OS::DebugBreak調用。如果我將代碼QJSEngine::evaluate換成__try-__exceptSEH),那麼應用程序不會崩潰,但此解決方案是Windows特定的。

問題:有沒有辦法在節點和Qt應用程序中以平臺無關的方式處理v8::internal::OS::DebugBreak

=== 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 

主.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; 
} 

回答

3

我不相信有一個跨平臺的方式來捕獲V8致命錯誤,但即使有,或者如果有什麼方法可以將它們吸引到您關心的所有平臺上,我不確定這會給您帶來什麼。

問題是,V8使用global flag記錄是否發生致命錯誤。一旦設置了該標誌,V8將拒絕任何嘗試創建新的JavaScript上下文,因此無論如何都沒有意義。嘗試執行一些良性的JavaScript代碼後捕捉到最初的致命錯誤。如果我是對的,你會馬上得到另一個致命的錯誤。

在我看來,正確的事情是Node和Qt將V8配置爲不會引發致命錯誤。既然V8支持隔離和內存約束,那麼處理查殺致命錯誤就不再合適。不幸的是,它看起來像V8的錯誤處理代碼還沒有完全支持這些新功能,並仍然假定內存不足的情況始終是不可恢復的。

+0

另請注意,您可以在使用V8 :: SetFatalErrorHandler()中止之前註冊一個回調,儘管這仍然不能讓您展開v8堆棧。您還可以使用--no-hard_abort來控制OS :: Abort(),以使進程安靜地退出(SIGABRT),而不是使用訪問衝突(V8_IMMEDIATE_CRASH())。 (我不確定在哪種情況下調用DebugBreak() - 可能只有在調試器被連接時)。 –