前段时间接到一个任务:对项目组的Web项目主画面进行性能优化。
画面情况是:监控设备数量200多台,画面每10秒钟查询并更新数据,如果不对比缓存每10s进行更新,那么在IE浏览器下15分钟不到增长了88MB(用F12内存工具查看),而且会一直增长,直至浏览器崩溃...
以JS生成的html代码主要结构如下(填入HTML上的DIV标签内,$('').html(...)):
<ul > <li><a><img /></a><div></div></li> <li><a><img /></a><div></div></li> ... <li><a><img /></a><div></div></li> <ul>
网上找了sIEve工具对web页面进行了分析,
结论是:
1,每10秒钟内存会增加1MB多但是释放的不过十几KB,js循环中大量DOM节点建立(UL,内部包括LI/DIV/A节点),但是从未释放,以至内存占用曲线就是上升直线,DOM对象曲线中观察DOM数量也是不停增加。最主要的是js中建立的UL元素始终是orphan(孤立)节点。
2,每10秒钟为画面中的一组checkbox绑定一次jquery.ui.button操作,每次都生成了很多DIV /SPANdom对象,都是孤立节点,占用的内存始终没被浏览器释放;
于是,针对结论1写了个函数准备每次重画UL列表前主动清除内部节点包括UL标签本身:
var releasememory3 = function(obj){ $(obj).find("a").unbind(); $(obj).find("li").unbind(); $("#rightmenu ul > li").unbind(); var li0 = $(obj).find("li").eq(0); removeLIAllsibling(li0); li0 = null; } var removeLIAllsibling = function(_elem){// var _parentElement = _elem.parentNode; if(_parentElement){ for (var i=0;i<_parentElement.childNodes.length;i++){ var childNode = _parentElement.childNodes[0]; // li var div0 = childNode.getElementsByTagName("DIV");//div for(var j=0;j<div0.length;j++){//div div0[j].innerHTML = ''; childNode.removeChild(div0[0]); } div0= null; var a0 = childNode.getElementsByTagName("A");//A for(var k=0;k<a0.length;k++){//A var img0 = a0[k].getElementsByTagName("IMG");//IMG for(var m=0;m<img0.length;m++){ a0[k].removeChild(img0[0]); } img0 = null; a0[0].onclick = null; childNode.removeChild(a0[0]); } a0 = null; childNode.onclick = null; _parentElement.removeChild(childNode); } } _parentElement = null; };
测试结果是此releasememory3函数成功清除了孤立节点IMG/DIV/A/LI,但是无法清除UL节点。
由于js建立的UL标签始终是孤立节点,故把ul放在JSP的html部分,在js中仅仅生成li节点;
再次测试清除,IMG/DIV/A/LI都可以释放;
从sIEve测试结果看这样改写后的LI/A/DIV/IMG节点都不再是孤立节点每次更新HTML DIV中的ul内部节点都可以被浏览器释放。结论1的问题解决。
针对结论2,由于循环不断给html画面上的input控件绑定juery.ui.button操作,查看jquery.ui.button.js库文件,确实每次都会建立span对象并绑定很多事件,这部分不属于画面代码,比较难以主动清除,所以,解决办法是只作一次jquery.ui.button的绑定操作,循环中只更新input label标签中的变化内容text属性。问题2解决。
比较明显的2个内存泄露问题解决。
列举问题可能的原因:
1, Js代码DOM孤立节点、
2, js全局变量滞留内存、
3, js代码DOM对象注册匿名函数闭包导致的循环引用、
4, js对象dom对象相互引用导致内存不释放、
5,一般 js闭包导致的循环引用导致内存不释放、
6, js隐式对象转换导致的对象创建不释放、
7, js中DOM节点增加顺序错误导致内存不释放、
8, js大量循环重复重写同一对象属性(新建很多对象不释放)
9, DOM对象绑定事件未清除(可能在引用库比较多)
10,卸载页面时直接解绑事件、删除全局变量(无法解决页面不跳转时的内存增长,解决画面切换时的内存增长)
引用其他经验者的一段启发性文字:
IE下的内存泄露原因就是循环引用,IE的垃圾回收器不能很好处理这种引用。 会产生泄露的循环引用,只有孤立的DOM对象(脱离DOM树)。 孤立的DOM对象间的循环引用,孤立的DOM对象与JS对象的循环引用。 为什么是孤立的DOM对象呢?在离开页面时(刷新,跳转)会删除整个DOM树,在DOM树上的对象也会被删除,就算有循环引用,此时被打断。 孤立的DOM对象有:一、用JS创建但未加入DOM树。二、从DOM树中删除的。 所以避免泄露,就尽量不要让这样的DOM对象产生。 有时候这样对象又不可避免,那就不要让这样对像产生循环引用。 最常见的循环引用是由闭包产生,其执行环境中的变量(包括参数)引用了DOM对象。
相关推荐
Vue 单页应用(SPA)优化是一项至关重要的工作,尤其是在现代 web 开发中,为了提供更好的用户体验,我们需要尽可能减少页面加载时间和提高性能。本文将详细介绍在 Vue 项目中进行优化的一些关键策略。 首先,我们...
4. **优化性能**:通过缓存、懒加载等技术优化DTree在大数据量下的性能。 在实际项目中,TestDTree可能是一个测试用例或者示例代码,用于演示DTree的正确使用和功能验证。开发者可以通过阅读和运行这些代码,更好地...
这篇小记主要关注了几个关键领域:持久层、MVC框架、视图层、JavaScript库以及缓存技术。下面将详细阐述这些知识点。 1. **持久层**: - **Hibernate**:是一个流行的ORM(对象关系映射)框架,允许开发者以面向...
JavaScript正则表达式是用于文本匹配的强大工具,它允许我们在文本中搜索特定的模式。在处理匹配字符串字面量时,正则表达式可以用来识别双引号内的文本内容。在提供的文章中,作者讨论了关于匹配字符串字面量的正则...
v12.x系列的更新主要是性能优化、错误修复以及对ES模块和HTTP/2等特性的增强。 Node.js的核心特性包括: 1. V8引擎:Node.js使用Google的V8 JavaScript引擎,使得JS代码能以接近原生的速度运行。 2. 非阻塞I/O:...
MySQL Shell是MySQL数据库管理系统的一个重要组件,主要用于交互式地执行SQL命令、JavaScript脚本和Python脚本,提供了一个全面的接口来管理和操作MySQL服务器。在本案例中,我们讨论的是MySQL Shell的8.0.20版本,...
描述中提到的"macos node-v12.17.0.7z"表明这个Node.js的版本是专门为macOS操作系统编译和优化的。macOS是苹果公司为其硬件产品如Mac电脑提供的操作系统,它具有用户友好的图形界面和强大的命令行工具。在macOS上...
2. **FlexPaper使用小记.mht**:这可能是一个关于如何使用Flexpaper的教程或笔记,MHT是一种单个文件的网页归档格式,包含了网页的所有内容。 3. **bi.pdf**和**bi.swf**:这两个文件可能是示例文档,用来测试...
3. **性能优化**:DisplayTag设计时考虑了性能问题,只加载当前页的数据,减少服务器负载。 4. **功能丰富**:除了分页,还包括列排序、筛选、导出(如CSV、PDF、Excel)等实用功能。 5. **兼容性**:DisplayTag与...
在很多情况下,IIS作为前端服务器,可以处理HTTP请求,提供静态资源(如HTML、CSS、JavaScript等),而Tomcat则作为一个应用服务器,负责运行Java Web应用程序。这种结合方式可以充分利用IIS的高并发性能和Tomcat对...
综上所述,EditPlus 3.0作为一个强大的编辑器,其丰富的功能和对JAVA的优化使其成为开发者的重要工具。无论是编写代码、调试程序还是管理项目,EditPlus都能提供高效便捷的解决方案。通过不断迭代和更新,EditPlus...