为什么异常会导致Node.js中的资源泄漏?

Jus*_*tin 24 javascript memory-leaks memory-management exception node.js

如果您查看的Node.js 文档的开头,它指出:

根据throw如何在JavaScript中工作的本质,几乎从来没有任何方法可以安全地"拾取你离开的地方",而不会泄漏引用,或者创建一些其他类型的未定义的脆弱状态.

再次在代码示例中,它在第一部分中给出了:

虽然我们已经阻止了突然重启过程,但我们正在疯狂地泄漏资源

我想明白为什么会这样?什么资源泄漏?他们建议您仅使用域来捕获错误并安全地关闭进程.这是所有例外的问题,而不仅仅是在使用域时?在Javascript中抛出和捕获异常是不好的做法吗?我知道这是Python中的常见模式.

编辑

我可以理解为什么如果抛出异常,非垃圾收集语言中可能存在资源泄漏,因为如果抛出异常,您可能运行的任何清理对象的代码都不会运行.

我可以用Javascript想象的唯一原因是抛出一个异常存储引用异常的范围内的变量引用(也许是调用堆栈中的东西),从而保持引用,然后异常对象被保留,从不得到清理.除非所提到的泄漏资源是引擎内部的资源.

UPDATE

我写了一篇博客,现在解释一下这个问题的答案.看看这个

Eri*_*ott 14

您需要担心的是意外的异常.如果您对应用程序的状态不够了解,无法为特定异常添加处理并管理任何必要的状态清理,那么根据定义,您的应用程序的状态是未定义的,并且是不可知的,并且很可能存在事物不应该挂在那周围.这不仅仅是内存泄漏,你不必担心.未知的应用程序状态可能会导致不可预测和不需要的应用程序行为(例如提供错误的输出 - 部分呈现的模板,或不完整的计算结果,或者更糟糕的是,每个后续输出都是错误的情况).这就是为什么在发生未处理的异常时退出进程很重要的原因.它为您的应用程序提供了自我修复的机会.

例外情况发生了,这没关系.接受它.关闭该过程并使用像Forever这样的东西来检测它并将其设置回正轨.集群和域名也很棒.您正在阅读的文本并不是针对抛出异常的注意事项,也不是在您处理了您期望的异常时继续执行该过程 - 这是在发生意外异常时保持流程运行的警告.

  • 您不应该只删除全局异常处理程序。在退出之前记录异常仍然非常有用。 (2认同)

B T*_*B T 11

我认为当他们说" 我们正在泄漏资源 "时,他们的确意味着" 我们可能会泄漏资源 ".如果http.createServer正确处理异常,则不应泄漏线程和套接字.但是,如果它不能正确处理事情,它们当然可能是.在一般情况下,您永远不会真正知道某些事情是否始终正确处理错误.

我认为他们错误/非常误导他们说" 通过JavaScript的本质如何在JavaScript中工作,几乎没有任何方法可以安全地...... ".关于throw如何在Javascript(与其他语言相比)中运行起来不应该让它变得不安全.一般来说,抛出/捕获的工作方式也没有什么可以使它不安全 - 除非你使用它们错了.

他们应该说的是,需要妥善处理特殊情况(无论是否使用例外情况).有几个不同的类别可以识别:

一个状态

  1. 外部状态(数据库写入,文件输出等)处于瞬态时发生的异常
  2. 共享内存处于临时状态时发生的异常
  3. 只有局部变量可能处于瞬态的例外情况

B.可逆性

  1. 可逆/可恢复状态(例如数据库回滚)
  2. 不可逆状态(丢失数据,未知如何反转或禁止反转)

C.数据关键性

  1. 数据可以废弃
  2. 必须使用数据(即使已损坏)

无论你正在搞砸什么类型的国家,如果你可以扭转局面,你应该这样做而且你已经确定了.问题是不可逆转的状态.如果您可以销毁损坏的数据(或将其隔离以进行单独检查),那么这是不可逆转状态的最佳举措.当抛出异常时,这会自动为局部变量完成,这就是为什么异常在处理纯功能代码中的错误(即没有可能的副作用的函数)方面表现优异的原因.同样,如果可以接受,则应删除任何共享状态或外部状态.在共享状态的情况下,要么抛出异常,直到共享状态变为本地状态,并通过展开堆栈(静态或通过GC)清理,或重新启动程序(我读过人们建议使用某些东西)像nodejitsu永远).对于外部状态,这可能更复杂.

最后一种情况是数据至关重要.好吧,那么你将不得不忍受你创造的错误.每个人都必须处理错误,但是当你的错误涉及到损坏的数据时,它是最糟糕的.这通常需要手动干预(重建丢失/损坏的数据,有选择地修剪等) - 在最后一种情况下,异常处理不会让你全程完成.

我在一些数据存储的多次更新的上下文中写了一个类似的答案,涉及如何处理各种情况下的中间操作失败:https://stackoverflow.com/a/28355495/122422


lak*_*tak 7

从node.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);
});
Run Code Online (Sandbox Code Playgroud)

在这种情况下,handleRequest在关闭套接字之前发生异常时,您正在泄漏连接.

"泄露"的意思是你完成了处理请求而没有事后清理.最终连接将超时并关闭套接字,但如果您的服务器处于高负载状态,它可能会在发生这种情况之前耗尽套接字.

根据您的操作,handleRequest您可能还会泄漏文件句柄,数据库连接,事件监听器等.

理想情况下,您应该处理异常,以便在它们之后进行清理.