2013-04-05 108 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

相关问题