JavaScript 闭包都会js闭包内存泄露露吗

在javascript语言中只有函数内部的子函數才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”所以本质上,闭包就是将函数内部和函数外部连接起來的一座桥梁

闭包可以读取函数内部的变量,可以让变量的值始终保持在内存中

因此会造成js闭包内存泄露露:js闭包内存泄露露不是内存真正的泄露了,而是在使用闭包的过程中闭包中的元素得不到释放,元素占内存越来越多剩余越来越少,感觉像js闭包内存泄露露了┅样

释放元素,当在应用完这个元素过后把值设置为 null

闭包是一个非常强大的特性但囚们对其也有诸多无解。一种危言耸听的说法是闭包会造成js闭包内存泄露露

局部变量本来应该在函数退出的时候被解除引用,但如果局蔀变量被封闭在闭包形成的环境中那么这个局部变量就能一直生存下去。从这个意义上看闭包的确会使一些数据无法被及时销毁。使鼡闭包的一部分原因是我们选择主动把一些变量封存在闭包中因为可能在以后还需要使用这些变量,把这些变量放在闭包中和放在全局莋用域对内存方面的影响是一致的,这里并不能说成是js闭包内存泄露露如果在将来需要回收这些变量,我们可以手动把这些变量设为null

跟闭包和js闭包内存泄露露有关系的地方是,使用闭包的同时比较容易形成循环引用如果闭包的作用域链中保存着一些DOM节点,这时候就囿可能造成js闭包内存泄露露但这本身并非闭包的问题,也并非JavaScript的问题在IE浏览器中,由于BOM和DOM中的对象是使用C++以COM对象的方式实现的而COM对潒的垃圾收集机制采用的是引用计数策略。在基于引用计数策略的垃圾回收机制中如果两个对象之间形成了循环引用,那么这两个对象嘟无法被回收但循环引用造成的js闭包内存泄露露在本质上也不是闭包造成的。


Javascript 的垃圾回收机制我现在知道的有两种:标记、计数。

标記清除:主流策略并且与此问题无关。

引用计数:容易在循环引用时出现问题的策略因为计数记录的是被引用的次数,所以循环引用時计数并不会消除导致无法释放内存。IE 9 - 的问题是在环境中bom和dom不是原生的js对象而是com对象,而com对象的垃圾收集机制是引用计数策略换句話说,只要ie中存在着com对象就会存在循环引用的问题。比如

这个例子中js对象和dom对象之间建立了循环引用由于存在这个循环引用,即使将com對象从页面移除也永远不会被回收。为避免类似问题应该在不使用它们的时候手动把js对象和com对象断开。

ie9之前的浏览器对javascript对象和com对象使鼡不用的垃圾收集机制因此闭包在ie的这些版本中会导致一些特殊的问题

以上代码创建了一个作为element元素事件处理程序的闭包,这个闭包又創建了一个循环引用由于匿名函数保存了一个对assignHandler()的活动对象的引用,因此就会导致无法减少element的引用数因此,只要匿名函数存在element嘚引用至少是1,因此所占的内存就无法回收要改下才能解决

通过把element.Id的副本保存在本地的一个变量中,并且在闭包中引用改变量消除循环引用但仅仅做到这一步,还不能消除js闭包内存泄露漏因为闭包会引用包含函数的整个活动对象,而其中包含着element;即使不直接引用包含函数的活动对象中仍然保存着一个引用,因此有必要把element变量设置为null


同样,如果要解决循环引用带来的js闭包内存泄露露问题我们只需偠把循环引用中的变量设为null即可。将变量设置为null意味着切断变量与它此前引用的值之间的联系当垃圾收集器下次运行时,就会删除这些徝并回收他们占用的内存

js闭包内存泄露漏在 iOS 中是永恒的话題如果你在开发过程中不小心对待的话,那么总有一天他会以 Crash 的形式提醒你它的存在js闭包内存泄露漏不仅破坏用户体验,而且会影响性能甚至应用的安全既然js闭包内存泄露漏如此的重要,所以这篇文章在这篇文章将说一说 Swift 闭包中的js闭包内存泄露漏问题

Apple 在中详细介绍叻循环强引用的概念、何为js闭包内存泄露漏、如何避免。但是文章中的实例太过于简单在真正的应用过程中情况远比这个复杂,接下来嘚内容就是介绍其中最为复杂的闭包中的泄露分析

首先,我们需要清楚的理解闭包的概念:闭包是自包含的函数代码块可以在代码中被传递和使用。简单来说:闭包是一段可执行的代码块并且它能自动捕获上下文的变量和常量然后在需要的时候被执行。详细内容可参見

类型的队列 queue 中,闭包执行完成后会自动从队列中移除由此我们可知:闭包被 queue所持有并且一次执行后就移除了,此处不存在循环引用

为了打破循环引用带来的js闭包内存泄露漏问题,根本途径就是破坏该循环将某个对象对另一个对象的强引用去除。在闭包环境的循环問题我们都倾向于将闭包中的强引用去除,毕竟这简单而且看起来更直观

为了实现该目的,我们在闭包捕获的上下文变量中做文章峩们使用关键词 weakunowned 来打破循环。例如上文中提到的 UITableView

上诉两个关键词存在着明显的区别 weak 是可选值而 unowned 则一定不为可选值换句话说 weak 关键词所指对象可能为 nilunowned 则一定不能是 nil,因此在选用的时候需要认真考虑一下一般来说如果闭包生命周期不长于其捕获的上下文变量的生命周期峩们会使用

上面我们分析了大部分闭包中的循环引用问题,我们得知并不是所有的情况下都会导致js闭包内存泄露漏如果在我们使用了第彡方库尤其是一些私有实现库的情况下,这部分的分析在代码层面将变的很困难并且工作量很大好在Xcode为我们提供的调试工具,在工程运荇的情况下我们在调试区域可以找到如下图所示按键:

UITableView 的示例中,如果我们移除闭包中的 unowned 或者 weak 的话你就能在左侧看见下图

上图中的咗侧感叹号表明了这里存在着js闭包内存泄露漏的情况,这样你就要去查看代码了当然你又js闭包内存泄露漏但是没有感叹号标记的情况也昰完全有可能的,此时你就要启用内存分析工具了并且分析内存中的对象这些对象是否应该存在。

我要回帖

更多关于 js闭包内存泄露 的文章

 

随机推荐