前几天我们的项目临上线出现了让人措手不及的Bug,特么的内存泄漏了。在一顿猛如虎的操作之后终于将这只小蛔虫抽了出来摔在地上踩死。为了纪念它给我的重创,我决定深入学习一下并写下博客记录下来。
提到内存泄漏的话有一个词和它很像,叫做“内存溢出”,让这哥儿俩自我介绍一下吧。
内存溢出(Out Of Memory):“你内存一共就剩1MB,非要存个1GB的数据,存小点不行吗?要不再加点内存空间好不好,还存,还存溢出了昂,一库一库~”
怎么样,是不是很像我们单身的时候把硬盘都下载红了的处境,哈哈哈~
内存泄漏(Memory Leak):“你声明了一个又一个局部引用变量,都用完了还不让垃圾回收,空间都被占用光了晓得不啦,快点把这块用不到的内存给老子释放了!”
不可否认这小哥儿俩脾气都还挺大的哈,毕竟占着房,躺着地,挪用人家资源,他可不是得给你好看嘛。
通过哥儿俩友好的自我介绍,我们发现了内存泄漏和内存溢出其实都是一件事,“占人家内存啦”。区别就是一个疯狂叠加,另一个占着内存又不用~
在js代码中的形成方式:
1,意外的全局变量
这种情况多数是coder无意的操作,将一个变量挂在了window对象上,误打误撞将它变成了全局变量。
请各位看官看上图,调用leaks函数时,this指向的是window~,leak1成了window的属性变量!leak2前面没有var保留字用来定义变量,leak2也被挂载到了window上,当我们打印出this的时候:
本来我们只是想创建一个属于new leaks()的成员变量,和在leaks函数中的局部变量。却误将它们都变成了全局变量,殊不知全局变量是不会被浏览器所回收的。他们就成了占用内存的冗余代码。
2,没有回收的计时器和事件委托
说到这里coding周期较长的官爷可以忽略了,无非就是在使用setInterval的时候忘了clearInterval清除掉,导致作用域内的元素长期处于激活状态无法释放。
这里稍稍多说一句,我们在代码中应尽量使用setTimeout来代替setInterval,setInterval在时间间隔很短的时候会产生回调堆积,所以代码中应尽量使用setTimeout延时递归来模拟setInterval。
—— 来自红宝书的咆哮
介里我们来聊聊事件的委托吧~
当我还是个刚入行的小白的时候给元素添加事件只用onClick并带有一脸无知的骄傲,这么简单方便的方法为什么不用,非要用个兼容性不好的addEventListener嘞?后来知道了事件委托的特点以及Dom0和Dom2的区别之后才发现事件委托真是个高效的发明~具体差别我就不在这里絮叨了。
当我们使用事件委托的方法给点击事件挂载了一个回调函数的时候⤵️
我们的console.log('addEvent click1')是委托在btn3按钮的click事件上的,等到下一行立马继续委托了console.log('addEvent click1'),所以当点击btn3按钮的时候,这两个console.log是都可以打印出来的~
所以呢!这个回调函数里的活动对象是一直被激活的状态的,不会被回收的.....起码在老IE浏览器下不会被回收~
现在的浏览器已经将这种操作失误导致的内存泄漏正确处理了,所以在chrome中是抓取不到这种回调的内存占用的。抓取了一天的我终于松了口气~
但是!!!
身为共产主义接班人的我们还是要在享受完工具的便利后将他们妥善的处理,比如在不需要事件委托的时候乖乖的将它删除
这样麻麻才不会说我们是乱丢玩具的小孩。
3,没有被清理的dom引用
这个危险点在项目中也是很常见的,毕竟在曾经的JQ时代我们经常要写对dom的操作嘛。
给位看官请看下面这个以哥簪剖:
当我们把从html中取到了一个ID为refA的元素赋值给了变量refA,然后我又删除掉了这个dom元素,页面上肯定空空如也了对不对。可是这个refA变量呢,还是在内存中保存着dom元素的信息的,不信?你来看:
我在window中还是能找到这个变量和它引用的dom信息,如果这个dom很大的话...
好在我们现在基本都是前后端分离开发,玩弄dom的时代已过,但是如果客爷您发现在递归引用dom之后浏览器变慢,那就要好好检查一番了哟。
4,闭包
说闭包内存泄漏真的是一个老生常谈的问题了,依稀记得刚入行的时候去面试,在说完闭包的作用之后一定要补一句在IE浏览器中会形成内存泄漏,当时也不知道到底为什么,死记硬背过面试呗。
在这里捎带啰嗦一句,因为早期IE是使用C/C++引擎,他们的垃圾回收机制是通过引用计数这种方式。所以闭包中的引用一直不清零就会形成泄漏,具体的垃圾回收机制请看在下的另一篇博文《前端内存泄漏之回收番》
简单撸个代码昂:
这样就形成了一个简单的闭包,将私有变量保存下来。来看看内存中的情况吧~
惊不惊喜,意不意外
leak这个变量真的没有被回收,还占了72b的空间。
以上就是这次分享的全部内容,这篇博客内容较多但没有一句废话全是干货,在下也是边学边记阅读了不少优秀的文章,如果有什么内容不恰当还请各位网友及时批评指正()。