Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

关于闭包的生存周期问题

  闭包(Scope)可以分为两种。一种是临时闭包(Function Scope),一种是可持续闭包(Closure)。他们的区别就是,临时闭包里的变量在函数运行结束就自动释放掉内存了。而可持续闭包就是局部变量有外部引用,导致函数运行结束后依然不释放内存。
setInterval(function(){
  var a=Array(1E7).join("0");
},16);
  首先是临时闭包,你会发现,这个匿名函数里面声明的变量在它运行结束时就自动释放内存了。就算使用setInterval连续调用它,也不会造成内存泄漏。这个代码在Chrome、FF、IE9、IE6,上测试过没问题,其他浏览器懒的测试了。这个匿名函数就是一个临时闭包,或者说普通的闭包都是临时闭包。这个没啥好讨论的,普通的闭包会可以自动释放内存的。
  接下来要登场的是今天的主角,可持续闭包。先看代码 var f;
(function(){
  //这儿放如一个超大的数据包
  var a=Array(1E8).join("0");
  //为这个闭包添加一个对外的接口
  f=function(){return a};
})();
  在这个代码中,我们在闭包内做了一个全局的接口。这时候即使闭包运行结束,它的内存也不会被释放。因为它知道自己的数据很有可能被接口使用到。大家应该知道,函数可以使用和它的声明同作用域的局部变量。这个接口函数和闭包内的a是同作用域的,所以接口函数内的a就指的是上面那个超大数据包a。这时候,f如果被调用,接口函数就必须返回这个a,所以它的内存无法被释放。这种情况就称为可持续闭包。这个代码是在Chrome上测试的,低版本浏览器要测试的话可能会内存溢出,可以试着调小里面的数据包大小再测试。
  那个,可持续闭包的内存可以释放吗?虽然确实可以释放,但是有兼容性上的问题。在Chrome和FF上可持续闭包的生存周期是在所有接口都被释放掉时结束的,但是IE上可持续闭包的内存无法被释放。至少我目前还没找到IE上释放它的方法。接着看下面代码 var f;
(function(){
  //这个放一个超大的数据包
  var a=Array(1E8).join("0");
  //为这个闭包添加一个对外的接口
  f=function(){return a};
})();

//文档被点击时释放掉f
document.onclick=function(){
  f=null;
};
  这个代码运行后,内存占用会超过100M,如果你使用的是Chrome或FF浏览器,点击文档后内存使用就会降下来(不会瞬间降下来,因为释放内存是一个复杂的过程,需要等待一段时间)。我就不截测试内存的图了,如果有兴趣自己去测试。另外,释放接口的时候别直接用delete去释放,delete是删除方法,是把对象从父对象中释放出来,和DOM的removeChild类似,这种方法会造成内存驻留。需要设置为null。
  所以,我们平时写程序的时候千万别把可持续闭包放入循环或递归中调用,那样必定造成内存泄漏。
网名:
54.144.24.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^