Open specialgirlgotoheaven opened 5 years ago
前端如何检查内存泄露?
(1).使用Chrome的开发者工具profiles来进行快照对比。
(2).如果是在Node环境下,可以用Node提供的process.memoryUsage()方法来检查内存泄露:
rss (resident set size) : 所有内存占用,包括指令区和堆栈。
heapTotal : "堆"占用的内存,包括用到的和未用到的。
heapUsed : 用到的堆。
external : V8引擎内部C++对象占用的内存。
判断内存泄露以heapUsed为准。
如何处理内存泄漏?
变量导致的内存泄露,将变量清除 a = null 即可。
事件监听导致的内存泄露,监听后移除即可
ES6 考虑到了这一点,推出了两种新的数据结构:WeakSet 和 WeakMap。它们对于值的引用都是不计入垃圾回收机制的,所以名字里面才会有一个"Weak",表示这是弱引用。
下面以 WeakMap 为例,看看它是怎么解决内存泄漏的。
const wm = new WeakMap(); const element = document.getElementById('example'); wm.set(element, 'some information'); wm.get(element) // "some information"
上面代码中,先新建一个 Weakmap 实例。然后,将一个 DOM 节点作为键名存入该实例,并将一些附加信息作为键值,一起存放在 WeakMap 里面。这时,WeakMap 里面对element的引用就是弱引用,不会被计入垃圾回收机制。
也就是说,DOM 节点对象的引用计数是1,而不是2。这时,一旦消除对该节点的引用,它占用的内存就会被垃圾回收机制释放。Weakmap 保存的这个键值对,也会自动消失。
基本上,如果你要往对象上添加数据,又不想干扰垃圾回收机制,就可以使用 WeakMap。
1.全局变量 2.setInterval 3.闭包 4.DOM引用 5.echart 6.事件监听(EventListener)
1、给DOM对象添加的属性是一个对象的引用。范例: var MyObject = {}; document.getElementById('myDiv').myProp = MyObject; 解决方法: 在window.onunload事件中写上: document.getElementById('myDiv').myProp = null;
2、DOM对象与JS对象相互引用。范例: function Encapsulator(element) { this.elementReference = element; element.myProp = this; } new Encapsulator(document.getElementById('myDiv')); 解决方法: 在onunload事件中写上: document.getElementById('myDiv').myProp = null;
3、给DOM对象用attachEvent绑定事件。范例: function doClick() {} element.attachEvent("onclick", doClick); 解决方法: 在onunload事件中写上: element.detachEvent('onclick', doClick);
4、从外到内执行appendChild。这时即使调用removeChild也无法释放。范例: var parentDiv = document.createElement("div"); var childDiv = document.createElement("div"); document.body.appendChild(parentDiv); parentDiv.appendChild(childDiv); 解决方法: 从内到外执行appendChild: var parentDiv = document.createElement("div"); var childDiv = document.createElement("div"); parentDiv.appendChild(childDiv); document.body.appendChild(parentDiv);
5、反复重写同一个属性会造成内存大量占用(但关闭IE后内存会被释放)。范例: for(i = 0; i < 5000; i++) { hostElement.text = "asdfasdfasdf"; } 这种方式相当于定义了5000个属性! 解决方法: 其实没什么解决方法:就是编程的时候尽量避免出现这种情况咯~~
但如果通过这么几个模式去check项目里的代码简直如大海捞针,我只有凭经验预测最有可能泄漏的几个点,再通过排除法,去掉先相关代码,再看内存是否泄漏。我预计会有以下几种情况造成泄漏:
频繁操作iframe 动态创建DOM 事件绑定 Ext框架本身 经过排查发现项目这么几个点内存泄漏较为严重:
对iframe里面的页面大量绑定键盘事件 在iframe里面的页面动态创建DOM iframe的刷新 Ext本身 对于这些问题我的解决方案如下:
离开iframe里的页面之前删除所有的事件绑定,删除所有动态创建的DOM 刷新iframe内容之前调用 iframe.contentWindow.document.write(''); iframe.contentWindow.document.close(); 强制释放iframe里的页面元素 修改Ext某些点。 比如Ext.getDOC() getDoc : function(){ //原实现 //return Ext.get(document); //修改后 var f = function() { }; f.prototype = Ext.Element.prototype; var docEl = new f(); docEl.dom = document; return docEl; } 具体是什么原因还没查清,不过修改后确实内存释放了不少。 修改Ext垃圾回收相关代码。及时删除垃圾回收的轮询。