2013-04-05 50 views
22

如果你看看開頭的Node.js的documentation for domains它指出:爲什麼異常會導致Node.js中的資源泄漏?

通過的拋在JavaScript中是如何工作的本質,幾乎從來沒有以任何方式安全地「拿起你離開的地方」 ,而不會泄露引用,或創建其他某種不明確的狀態。

同樣的代碼示例它給在首節它說:

像瘋了似的

雖然我們避免突然的重啓過程中,我們都滲出資源,我想理解爲什麼會出現這種情況?什麼資源在泄漏?他們建議您只使用域來捕獲錯誤並安全地關閉進程。這是所有例外的問題,而不僅僅是在使用域時?在Javascript中拋出和捕獲異常是一種不好的做法嗎?我知道這是Python中的一種常見模式。

編輯

我可以理解爲什麼有可能是資源泄漏在非垃圾回收的語言,如果你拋出一個異常,因爲那時的任何代碼可能會運行清理對象將無法運行如果有異常拋出。

我可以用Javascript想象的唯一原因是如果拋出異常將異常存儲引用引發到引發異常的範圍(也可能是調用堆棧中的東西),從而引用周圍,然後異常對象是保持在周圍,永遠不會清理乾淨。除非所引用的泄漏資源是引擎內部的資源。

UPDATE

我寫了一個博客解釋這個問題的答案會好一點吧。 Check it out

+0

你介意覺得這個問題非常有用http://stackoverflow.com/問題/ 14301839/javascript-asynchronous-exception-handling-with-node-js – 2013-04-06 18:37:47

+1

不幸的是,這個問題剛剛討論了使用域來捕獲異步異常。它根本沒有提到內存泄漏。 – 2013-04-07 05:11:53

+1

這就是爲什麼它是一個評論,而不是答案:)這是如何使域名嘗試/捕捉更容易處理。至於這個問題,這是關於關閉泄漏。你拋出一個異常,但你有例如一個請求對象,它仍然在事件中有一個引用,並且這個事件引用了請求對象,而這兩個對象並沒有被垃圾回收。例如,如果你有一個MongoDB連接,因爲引發異常你不關閉它,它可能隱含地保持打開狀態。 – 2013-04-07 05:20:27

回答

14

意外的例外是您需要擔心的例外。如果您對應用程序的狀態瞭解不多,無法爲特定的異常添加處理,並管理任何必要的狀態清理,那麼根據定義,您的應用程序的狀態是未定義的,而且是不可知的,並且很可能有事物掛在那不該是。這不僅僅是你不必擔心的內存泄漏。未知的應用程序狀態可能導致不可預知的和不需要的應用程序行爲(例如,提供錯誤的輸出 - 部分呈現的模板或不完整的計算結果,或者更糟糕的情況,即每個後續輸出都是錯誤的)。這就是爲什麼當發生未處理的異常時退出進程非常重要。它使您的應用程序有機會自行修復。

發生異常,這很好。擁抱它。關閉進程並使用像Forever這樣的東西來檢測它並將事情重新設置正確。集羣和域也很棒。您正在閱讀的文本不是針對拋出異常的警告,或是在處理您期望的異常時繼續執行的過程 - 這是在發生意外異常時保持流程運行的警告。

+0

感謝您的解釋。我實際上已經永遠用來管理我的流程了。我有一些使用Socket.io的服務器,並維護一些活動的websocket。如果發生異常,我擔心必須關閉服務器,因爲這意味着斷開所有其他客戶端的連接。我嘗試處理每個異常,並刪除全局異常處理程序。我只是永遠使用,如果它實際上因任何原因崩潰。再次感謝! – 2013-04-08 14:29:42

+1

你不應該只是刪除你的全局異常處理程序。在退出之前記錄異常仍然非常有用。 – laktak 2013-04-08 15:13:48

+0

@chris這是真的,但是因爲我永遠用來管理我的日誌,所以不處理它崩潰的異常,轉儲出堆棧跟蹤,然後永遠重新啓動它。所以我仍然記錄下來,可以回去查看堆棧跟蹤。 – 2013-04-10 15:22:16

7

從節點中取樣。JS文件:

var d = require('domain').create(); 
d.on('error', function(er) { 
    // The error won't crash the process, but what it does is worse! 
    // Though we've prevented abrupt process restarting, we are leaking 
    // resources like crazy if this ever happens. 
    // This is no better than process.on('uncaughtException')! 
    console.log('error, but oh well', er.message); 
}); 
d.run(function() { 
    require('http').createServer(function(req, res) { 
    handleRequest(req, res); 
    }).listen(PORT); 
}); 

在這種情況下,當你關閉套接字之前發生異常的handleRequest您正在泄漏的連接。

「泄漏」意味着您完成了處理請求而未事後清理。最終,連接將超時並關閉套接字,但是如果您的服務器處於高負載狀態,則可能在套接字發生之前耗盡套接字。

根據您在handleRequest做什麼,你也可以泄露的文件句柄,數據庫連接,事件監聽器等

理想情況下,你應該處理您的異常,所以你可以在他們之後清理。

+0

感謝您的回答。這符合其他人的說法,但這是一個很好的解釋。 – 2013-04-08 14:33:25

10

我認爲當他們說「我們正在泄漏資源」,他們真正的意思是「我們可能漏水資源」。如果http.createServer正確處理異常,線程和套接字不應該泄漏。但是,如果它不能正確處理事情,它們肯定會是。在一般情況下,你永遠不會真的知道是否有東西一直處理錯誤。

我認爲他們是錯誤/非常誤導他們說「由JavaScript的性能如何投擲,幾乎沒有任何方法可以安全地......」。不應該有任何關於如何在Javascript中使用throw(相對於其他語言),這使得它不安全。關於throw/catch在一般情況下是如何工作的,這也是不安全的 - 除非你錯誤地使用它們。

他們應該說的是,例外情況(無論是否使用例外情況)都需要適當處理。有幾個不同的類別來識別:

A.國家發生

  1. 例外,而外部狀態(數據庫寫入,文件輸出等)處於過渡狀態,同時共享發生
  2. 例外內存是處於過渡狀態
  3. 例外只有局部變量可能是處於過渡狀態

B.可逆性

  1. 可逆/可逆的狀態(例如數據庫回滾)
  2. 不可逆狀態(丟失的數據,未知如何扭轉,或禁止逆轉)

C.數據臨界

  1. 數據可以報​​廢
  2. 必須使用數據(即使損壞)

不管你搞亂的狀態是什麼類型,如果你能扭轉這種狀態,你應該這樣做,然後你就成了。問題是不可逆轉的狀態。如果您可以銷燬損壞的數據(或將其隔離以進行單獨檢查),那麼這是不可逆轉狀態的最佳舉措。當拋出異常時,這是爲局部變量自動完成的,這就是爲什麼異常擅長處理純功能代碼中的錯誤(即沒有可能的副作用的函數)的原因。同樣,如果可以接受,則應刪除任何共享狀態或外部狀態。在共享狀態下,要麼拋出異常,直到共享狀態變爲本地狀態,並通過展開堆棧(靜態或通過GC)來清理,或者重新啓動程序(我已經讀過人們建議使用某些東西像nodejitsu永遠)。對於外部狀態,這可能更復雜。

最後一種情況是數據嚴重時。那麼,你將不得不忍受你創造的錯誤。每個人都必須處理錯誤,但是當你的錯誤涉及損壞的數據時,它是最糟糕的。這通常需要人工干預(重建丟失/損壞的數據,選擇修剪等) - 在最後一種情況下,異常處理將無法完成整個過程。

我寫了有關如何處理各種情況下的中期工作不良多個更新的一些數據存儲上下文了類似的回答:https://stackoverflow.com/a/28355495/122422

+0

感謝您的回答。我非常同意。我認爲這些文檔充其量是誤導性的,而且在這個問題上非常不明確。在第一次看到我正在考慮的文檔後,爲什麼他們會提供一種方法來拋出和捕獲異常,如果它在語言中的工作方式有內在的錯誤?這是一種常見的模式,其他語言似乎很好。 我不認爲'http.createServer()'有辦法正確處理異常並在域之前進行清理。我仍然相信Node.js需要Python風格的上下文管理器。 – 2013-04-10 15:37:51

+1

順便說一句,我昨晚寫了一個[blog](http://www.teknically-speaking.com/2013/04/javascript-and-nodejs-exceptions-and.html),我剛剛更新了它,並且鏈接到你的答案在這裏。 – 2013-04-10 17:06:21

相關問題