3

使用我最近发现的 chrome 开发工具,我使用模块化概念的应用程序会在内存中留下一些 Module 对象,即使它们没有被我的任何其他应用程序对象直接引用。

这里的问题似乎是,它们在某些函数范围内被引用。

正如您在以下屏幕截图中看到的:

在此处输入图像描述

函数范围中有很多引用。

这是一小部分代码,它演示了在我的应用程序中如何发生这种情况的多种方式之一。由于module在里面someCallback引用了一个引用,所以我不能再删除自己了。

function augmentModule(core, module){

   var someCallback = function(){
      module.stop();
   };

   module.listenTo(core, "someEvent", someCallback);
}

我的问题是:

这是我必须担心的真正的内存泄漏,还是这个对象会在稍后被 JavaScript 引擎垃圾收集?JavaScript 引擎是否知道“此对象仅从函数和闭包范围引用,并且没有“真实”引用,因此我可以删除它。” ?

4

3 回答 3

2

在您的示例中,没有实际问题。变量“模块”是从函数中引用的,因此只要有人保留该函数,它就会被保留。这是绝对合法的,因为你的函数一旦被调用就需要这个对象。当你的函数被释放时,这个引用就会消失。

但是,您应该意识到更微妙的事情。如果你应该在 main 函数中有多个闭包,它们都共享一个作用域存储。这意味着,一些引用可以保存在一个闭包中,甚至不需要它们:

function m(ref0, ref1, ref2, ref3) {
   var cb1 = function(){
     return ref1 + ref2;
   };
   function notCurentlyUsed(){
     return ref2 + ref3;
   };
   ref0.doSomething();
   return cb1;
}

所以,

  • ref0 与闭包无关,它在 m 完成时被释放,
  • ref1 被保留,cb1 需要它,所以它进入 cb1 保留的范围存储,
  • ref2 被保留,cb1 和 notCurentlyUsed 都需要它,所以它进入 cb1 保留的范围存储,
  • ref3 也是保留的,只有 notCurentlyUsed 需要,但是作用域结构是共享的,所以 cb1 也保留。

请注意,您可以查看开发人员工具中实际保留的内容,因为函数值公开了它的 .

于 2013-05-14T22:37:22.463 回答
2

一种方法是在您的模块子类(augmenModule)中实现拆卸方法。teardown 方法将解除类在初始化时设置的所有观察者函数的绑定。在处理对象时调用您的拆卸方法以释放引用并允许对关联的内存进行垃圾收集。

于 2013-05-08T04:34:00.880 回答
0

请展开距离最小的最顶层保持器的树。实际上,这棵树是图表的一部分,它使您的对象保持活力。

所以你应该在你的应用程序的设计中找出保持器树中的对象,它直接或间接地保持对必须收集的“模块”对象的引用。这个参考将是问题的根源。您可能有很多这样的参考资料。在这种情况下,您必须消除所有这些。

于 2013-05-11T05:58:46.717 回答