- 浏览: 5160433 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
silence19841230:
先拿走看看
SpringBoot2.0开发WebSocket应用完整示例 -
wallimn:
masuweng 写道发下源码下载地址吧!三个相关文件打了个包 ...
SpringBoot2.0开发WebSocket应用完整示例 -
masuweng:
发下源码下载地址吧!
SpringBoot2.0开发WebSocket应用完整示例 -
masuweng:
SpringBoot2.0开发WebSocket应用完整示例 -
wallimn:
水淼火 写道你好,我使用以后,图标不显示,应该怎么引用呢,谢谢 ...
前端框架iviewui使用示例之菜单+多Tab页布局
写了好长时间javascript小功能模块,从来没有关注过内存泄漏问题。记得以前写C++程序的时候,内存泄漏是个严重的问题,我想是时候关注一下了。网上找了篇文章,Mark一下。原文地址:http://www.blogjava.net/tim-wu/archive/2006/05/29/48729.html
常规循环引用内存泄漏和Closure内存泄漏
要了解javascript的内存泄漏问题,首先要了解的就是javascript的GC原理。
我记得原来在犀牛书《JavaScript: The Definitive Guide》中看到过,IE使用的GC算法是计数器,因此只碰到循环 引用就会造成memory leakage。后来一直觉得和观察到的现象很不一致,直到看到Eric的文章,才明白犀牛书的说法没有说得很明确,估计该书成文后IE升级过算法吧。 在IE 6中,对于javascript object内部,jscript使用的是mark-and-sweep算法,而对于javascript object与外部object(包括native object和vbscript object等等)的引用时,IE 6使用的才是计数器的算法。
Eric Lippert在http://blogs.msdn.com/ericlippert/archive/2003/09/17/53038.aspx一文中提到IE 6中JScript的GC算法使用的是nongeneration mark-and-sweep。对于javascript对算法的实现缺陷,文章如是说:
"The benefits of this approach are numerous, but the principle benefit is that circular references are not leaked unless the circular reference involves an object not owned by JScript. "
也就是说,IE 6对于纯粹的Script Objects间的Circular References是可以正确处理的,可惜它处理不了的是JScript与Native Object(例如Dom、ActiveX Object)之间的Circular References。
所以,当我们出现Native对象(例如Dom、ActiveX Object)与Javascript对象间的循环引用时,内存泄露的问题就出现了。当然,这个bug在IE 7中已经被修复了[http://www.quirksmode.org/blog/archives/2006/04/ie_7_and_javasc.html]。
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp 中有个示意图和简单的例子体现了这个问题:
上面这个例子,看似很简单就能够解决内存泄露的问题。可惜的是,当我们的代码中的结构复杂了以后,造成循环引用的原因开始变得多样,我们就没法那么容易观察到了,这时候,我们必须对代码进行仔细的检查。
尤其是当碰到Closure,当我们往Native对象(例如Dom对象、ActiveX Object)上绑定事件响应代码时,一个不小心,我们就会制造出Closure Memory Leak。其关键原因,其实和前者是一样的,也是一个跨javascript object和native object的循环引用。只是代码更为隐蔽,这个隐蔽性,是由于javascript的语言特性造成的。但在使用类似内嵌函数的时候,内嵌的函数有拥有一 个reference指向外部函数的scope,包括外部函数的参数,因此也就很容易造成一个很隐蔽的循环引用,例如:
DOM_Node.onevent ->function_object.[ [ scope ] ] ->scope_chain ->Activation_object.nodeRef ->DOM_Node。
[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp]有个例子极深刻地显示了该隐蔽性:
还有这个例子在IE 6中同样原因会引起泄露
btw:
关于Closure的知识,大家可以看看http://jibbering.com/faq/faq_notes/closures.html这篇文章,习惯中文也可以看看zkjbeyond的blog,他对Closure这篇文章进行了简要的翻译:http://www.blogjava.net/zkjbeyond/archive/2006/05/19/47025.html。 之所以会有这一系列的问题,关键就在于javascript是种函数式脚本解析语言,因此javascript中“函数中的变量的作用域是定义作用域,而 不是动态作用域”,这点在犀牛书《JavaScript: The Definitive Guide》中的“Funtion”一章中有所讨论。
http://support.microsoft.com/default.aspx?scid=KB;EN-US;830555中也对这个问题举了很详细的例子。
一些 简单的解决方案
目前大多数ajax前端的javascript framework都利用对事件的管理,解决了该问题。
如果你需要自己解决这个问题,可以参考以下的一些方法:
http://outofhanwell.com/ieleak/index.php?title=Main_Page:有个不错的检测工具
http://youngpup.net/2005/0221010713 中提到:可以利用递归Dom树,解除event绑定,从而解除循环引用:
而http://novemberborn.net/javascript/event-cache一文中则通过增加EventCache,从而给出一个相对结构化的解决方案
使用方法也很简单:
http://talideon.com/weblog/2005/03/js-memory-leaks.cfm 一文中的方法类似:
使用起来也很简单
google map api同样提供了一个类似的函数用在页面的unload事件中,解决Closure带来的内存泄露问题。
当然,如果你不嫌麻烦,你也可以为每个和native object有关的就阿vascript object编写一个destoryMemory函数,用来手动调用,从而手动解除Dom对象的事件绑定。
还有一种就是不要那么OO,抛弃Dom的一些特性,用innerHTML代替appendChild,避开循环引用。详细见http://birdshome.cnblogs.com/archive/2005/02/16/104967.html中的讨论贴。
Cross-Page Leaks
Cross-Page Leaks和下一节提到的Pseudo-Leaks在我看来,就是IE的bug, 虽然MS死皮赖脸不承认:)
大家可以看看这段例子代码:
LeakMemory和CleanMemory这两段函数的唯一区别就在于他们的代码的循序,从代码上看,两段代码的逻辑都没有错。
但LeakMemory却会造成泄露。原因是LeakMemory()会先建立起parentDiv和childDiv之间的连接,这时候,为了让 childDiv能够获知parentDiv的信息,因此IE需要先建立一个临时的scope对象。而后parentDiv建立了和 hostElement对象的联系,parentDiv和childDiv直接使用页面document的scope。可惜的是,IE不会释放刚才那个临 时的scope对象的内存空间,直到我们跳转页面,这块空间才能被释放。而CleanMemory函数不同,他先把parentDiv和 hostElement建立联系,而后再把childDiv和parentDiv建立联系,这个过程不需要单独建立临时的scope,只要直接使用页面 document的scope就可以了, 所以也就不会造成内存泄露了
详细原因,大家可以看看http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp这篇文章。
btw:
IE 6中垃圾回收算法,就是从那些直接"in scope"的对象开始进行mark清除的:
Every variable which is "in scope" is called a "scavenger". A scavenger may refer to a number, an object, a string, whatever. We maintain a list of scavengers – variables are moved on to the scav list when they come into scope and off the scav list when they go out of scope.
Pseudo-Leaks
这个被称为“秀逗泄露”真是恰当啊:)
看看这个例子:
MS是这么解释的,这不是内存泄漏。如果您创建了许多无法获得也无法释放的对象,那才是内存泄漏。在这里,您将创建许多元素,Internet Explorer 需要保存它们以正确呈现页面。Internet Explorer 并不知道您以后不会运行操纵您刚刚创建的所有这些对象的脚本。当页面消失时(当您浏览完,离开浏览器时)会释放内存。它不会泄漏。当销毁页面时,会中断循 环引用。
唉~~~
详细原因,大家可以看看http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp这篇文章。
其它一些琐碎的注意点
变量定义一定要用var,否则隐式声明出来的变量都是全局变量,不是局部变量;
全局变量没用时记得要置null;
注意正确使用delete,删除没用的一些函数属性;
注意正确使用try...cache,确保去处无效引用的代码能被正确执行;
open出来的窗口即使close了,它的window对象还是存在的,要记得删除引用;
frame和iframe的情况和窗口的情况类似。
参考资料
http://jibbering.com/faq/faq_notes/closures.html
http://javascript.weblogsinc.com/2005/03/07/javascript-memory-leaks/
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp
http://72.14.203.104/search?q=cache:V9Bt4_HBzQ8J:jgwebber.blogspot.com/2005/01/dhtml-leaks-like-sieve.html+DHTML+Leaks+Like+a+Sieve+&hl=zh-CN&ct=clnk&cd=9 (这是DHTML Leaks Like a Sieve)一文在google上的cache,原文已经连不上了)
http://spaces.msn.com/siteexperts/Blog/cns!1pNcL8JwTfkkjv4gg6LkVCpw!338.entry
http://support.microsoft.com/default.aspx?scid=KB;EN-US;830555
http://www.ajaxtopics.com/leakpatterns.html
http://blogs.msdn.com/ericlippert/archive/2003/09/17/53028.aspx
http://www.quirksmode.org/blog/archives/2005/02/javascript_memo.html
http://youngpup.net/2005/0221010713
http://blogs.msdn.com/ericlippert/archive/2003/09/17/53038.aspx =
http://support.microsoft.com/kb/266071/EN-US ==>IE 5.0至5.5一些版本中的GC bug
http://www.quirksmode.org/blog/archives/2006/04/ie_7_and_javasc.html ==>ie 7的改进
http://erik.eae.net/archives/2006/04/26/23.23.02/ ==>ie 7的改进
http://www.feedbackarchive.com/spamvampire/today.html ==> Try this script for memory leaks - it leaked 50 megabytes in 15 minutes with firefox on linux:
http://birdshome.cnblogs.com/archive/2005/02/15/104599.html
http://www.quirksmode.org/dom/innerhtml.html
http://www.crockford.com/javascript/memory/leak.html
《JavaScript: The Definitive Guide》4th Edition
http://outofhanwell.com/ieleak/index.php?title=Main_Page
常规循环引用内存泄漏和Closure内存泄漏
要了解javascript的内存泄漏问题,首先要了解的就是javascript的GC原理。
我记得原来在犀牛书《JavaScript: The Definitive Guide》中看到过,IE使用的GC算法是计数器,因此只碰到循环 引用就会造成memory leakage。后来一直觉得和观察到的现象很不一致,直到看到Eric的文章,才明白犀牛书的说法没有说得很明确,估计该书成文后IE升级过算法吧。 在IE 6中,对于javascript object内部,jscript使用的是mark-and-sweep算法,而对于javascript object与外部object(包括native object和vbscript object等等)的引用时,IE 6使用的才是计数器的算法。
Eric Lippert在http://blogs.msdn.com/ericlippert/archive/2003/09/17/53038.aspx一文中提到IE 6中JScript的GC算法使用的是nongeneration mark-and-sweep。对于javascript对算法的实现缺陷,文章如是说:
"The benefits of this approach are numerous, but the principle benefit is that circular references are not leaked unless the circular reference involves an object not owned by JScript. "
也就是说,IE 6对于纯粹的Script Objects间的Circular References是可以正确处理的,可惜它处理不了的是JScript与Native Object(例如Dom、ActiveX Object)之间的Circular References。
所以,当我们出现Native对象(例如Dom、ActiveX Object)与Javascript对象间的循环引用时,内存泄露的问题就出现了。当然,这个bug在IE 7中已经被修复了[http://www.quirksmode.org/blog/archives/2006/04/ie_7_and_javasc.html]。
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp 中有个示意图和简单的例子体现了这个问题:
< html > < head > < script language = " JScript " > var myGlobalObject; function SetupLeak() // 产生循环引用,因此会造成内存泄露 { // First set up the script scope to element reference myGlobalObject = document.getElementById( " LeakedDiv " ); // Next set up the element to script scope reference document.getElementById( " LeakedDiv " ).expandoProperty = myGlobalObject; } function BreakLeak() // 解开循环引用,解决内存泄露问题 { document.getElementById( " LeakedDiv " ).expandoProperty = null ; } </ script > </ head > < body onload = " SetupLeak() " onunload = " BreakLeak() " > < div id = " LeakedDiv " ></ div > </ body > </ html >
上面这个例子,看似很简单就能够解决内存泄露的问题。可惜的是,当我们的代码中的结构复杂了以后,造成循环引用的原因开始变得多样,我们就没法那么容易观察到了,这时候,我们必须对代码进行仔细的检查。
尤其是当碰到Closure,当我们往Native对象(例如Dom对象、ActiveX Object)上绑定事件响应代码时,一个不小心,我们就会制造出Closure Memory Leak。其关键原因,其实和前者是一样的,也是一个跨javascript object和native object的循环引用。只是代码更为隐蔽,这个隐蔽性,是由于javascript的语言特性造成的。但在使用类似内嵌函数的时候,内嵌的函数有拥有一 个reference指向外部函数的scope,包括外部函数的参数,因此也就很容易造成一个很隐蔽的循环引用,例如:
DOM_Node.onevent ->function_object.[ [ scope ] ] ->scope_chain ->Activation_object.nodeRef ->DOM_Node。
[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp]有个例子极深刻地显示了该隐蔽性:
< html > < head > < script language = " JScript " > function AttachEvents(element) { // This structure causes element to ref ClickEventHandler //element有个引用指向函数ClickEventHandler() element.attachEvent( " onclick " , ClickEventHandler); function ClickEventHandler() { // This closure refs element //该函数有个引用指向AttachEvents(element)调用Scope,也就是执行了参数element。 } } function SetupLeak() { // The leak happens all at once AttachEvents(document.getElementById( " LeakedDiv " )); } </ script > </ head > < body onload = " SetupLeak() " onunload = " BreakLeak() " > < div id = " LeakedDiv " ></ div > </ body > </ html >
还有这个例子在IE 6中同样原因会引起泄露
function leakmaybe() { var elm = document.createElement( " DIV " ); elm.onclick = function () { return 2 + 2 ; } } for ( var i = 0 ; i 10000 ; i ++ ) { leakmaybe(); }
btw:
关于Closure的知识,大家可以看看http://jibbering.com/faq/faq_notes/closures.html这篇文章,习惯中文也可以看看zkjbeyond的blog,他对Closure这篇文章进行了简要的翻译:http://www.blogjava.net/zkjbeyond/archive/2006/05/19/47025.html。 之所以会有这一系列的问题,关键就在于javascript是种函数式脚本解析语言,因此javascript中“函数中的变量的作用域是定义作用域,而 不是动态作用域”,这点在犀牛书《JavaScript: The Definitive Guide》中的“Funtion”一章中有所讨论。
http://support.microsoft.com/default.aspx?scid=KB;EN-US;830555中也对这个问题举了很详细的例子。
一些 简单的解决方案
目前大多数ajax前端的javascript framework都利用对事件的管理,解决了该问题。
如果你需要自己解决这个问题,可以参考以下的一些方法:
http://outofhanwell.com/ieleak/index.php?title=Main_Page:有个不错的检测工具
http://youngpup.net/2005/0221010713 中提到:可以利用递归Dom树,解除event绑定,从而解除循环引用:
if (window.attachEvent) { var clearElementProps = [ 'data', 'onmouseover', 'onmouseout', 'onmousedown', 'onmouseup', 'ondblclick', 'onclick', 'onselectstart', 'oncontextmenu' ]; window.attachEvent("onunload", function() { var el; for(var d = document.all.length;d--;){ el = document.all[d]; for(var c = clearElementProps.length;c--;){ el[clearElementProps[c]] = null; } } }); }
而http://novemberborn.net/javascript/event-cache一文中则通过增加EventCache,从而给出一个相对结构化的解决方案
/* EventCache Version 1.0 Copyright 2005 Mark Wubben Provides a way for automagically removing events from nodes and thus preventing memory leakage. See <http://novemberborn.net/javascript/event-cache> for more information. This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/> */ /* Implement array.push for browsers which don't support it natively. Please remove this if it's already in other code */ if (Array.prototype.push == null ){ Array.prototype.push = function (){ for ( var i = 0 ; i < arguments.length; i ++ ){ this [ this .length] = arguments[i]; }; return this .length; }; }; /* Event Cache uses an anonymous function to create a hidden scope chain. This is to prevent scoping issues. */ var EventCache = function (){ var listEvents = []; return { listEvents : listEvents, add : function (node, sEventName, fHandler, bCapture){ listEvents.push(arguments); }, flush : function (){ var i, item; for (i = listEvents.length - 1 ; i >= 0 ; i = i - 1 ){ item = listEvents[i]; if (item[ 0 ].removeEventListener){ item[ 0 ].removeEventListener(item[ 1 ], item[ 2 ], item[ 3 ]); }; /* From this point on we need the event names to be prefixed with 'on" */ if (item[ 1 ].substring( 0 , 2 ) != " on " ){ item[ 1 ] = " on " + item[ 1 ]; }; if (item[ 0 ].detachEvent){ item[ 0 ].detachEvent(item[ 1 ], item[ 2 ]); }; item[ 0 ][item[ 1 ]] = null ; }; } }; }();
使用方法也很简单:
<script type="text/javascript"> function addEvent(oEventTarget, sEventType, fDest){ if(oEventTarget.attachEvent){ oEventTarget.attachEvent("on" + sEventType, fDest); } elseif(oEventTarget.addEventListener){ oEventTarget.addEventListener(sEventType, fDest, true); } elseif(typeof oEventTarget[sEventType] == "function"){ var fOld = oEventTarget[sEventType]; oEventTarget[sEventType] = function(e){ fOld(e); fDest(e); }; } else { oEventTarget[sEventType] = fDest; }; /* Implementing EventCache for all event systems */ EventCache.add(oEventTarget, sEventType, fDest, true); }; function createLeak(){ var body = document.body; function someHandler(){ return body; }; addEvent(body, "click", someHandler); }; window.onload = function(){ var i = 500; while(i > 0){ createLeak(); i = i - 1; } }; window.onunload = EventCache.flush; </script>
http://talideon.com/weblog/2005/03/js-memory-leaks.cfm 一文中的方法类似:
/* * EventManager.js * by Keith Gaughan * * This allows event handlers to be registered unobtrusively, and cleans * them up on unload to prevent memory leaks. * * Copyright (c) Keith Gaughan, 2005. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * (CPL) which accompanies this distribution, and is available at * http://www.opensource.org/licenses/cpl.php * * This software is covered by a modified version of the Common Public License * (CPL), where Keith Gaughan is the Agreement Steward, and the licensing * agreement is covered by the laws of the Republic of Ireland. */ // For implementations that don't include the push() methods for arrays. if ( ! Array.prototype.push) { Array.prototype.push = function (elem) { this [ this .length] = elem; } } var EventManager = { _registry: null , Initialise: function () { if ( this ._registry == null ) { this ._registry = []; // Register the cleanup handler on page unload. EventManager.Add(window, " unload " , this .CleanUp); } }, /* * * Registers an event and handler with the manager. * * @param obj Object handler will be attached to. * @param type Name of event handler responds to. * @param fn Handler function. * @param useCapture Use event capture. False by default. * If you don't understand this, ignore it. * * @return True if handler registered, else false. */ Add: function (obj, type, fn, useCapture) { this .Initialise(); // If a string was passed in, it's an id. if ( typeof obj == " string " ) { obj = document.getElementById(obj); } if (obj == null || fn == null ) { return false ; } // Mozilla/W3C listeners? if (obj.addEventListener) { obj.addEventListener(type, fn, useCapture); this ._registry.push({obj: obj, type: type, fn: fn, useCapture: useCapture}); return true ; } // IE-style listeners? if (obj.attachEvent && obj.attachEvent( " on " + type, fn)) { this ._registry.push({obj: obj, type: type, fn: fn, useCapture: false }); return true ; } return false ; }, /* * * Cleans up all the registered event handlers. */ CleanUp: function () { for ( var i = 0 ; i < EventManager._registry.length; i ++ ) { with (EventManager._registry[i]) { // Mozilla/W3C listeners? if (obj.removeEventListener) { obj.removeEventListener(type, fn, useCapture); } // IE-style listeners? else if (obj.detachEvent) { obj.detachEvent( " on " + type, fn); } } } // Kill off the registry itself to get rid of the last remaining // references. EventManager._registry = null ; } };
使用起来也很简单
<html> <head> <script type=text/javascript src=EventManager.js></script> <script type=text/javascript> function onLoad() { EventManager.Add(document.getElementById(testCase),click,hit ); returntrue; } function hit(evt) { alert(click); } </script> </head> <body onload='javascript: onLoad();'> <div id='testCase' style='width:100%; height: 100%; background-color: yellow;'> <h1>Click me!</h1> </div> </body> </html>
google map api同样提供了一个类似的函数用在页面的unload事件中,解决Closure带来的内存泄露问题。
当然,如果你不嫌麻烦,你也可以为每个和native object有关的就阿vascript object编写一个destoryMemory函数,用来手动调用,从而手动解除Dom对象的事件绑定。
还有一种就是不要那么OO,抛弃Dom的一些特性,用innerHTML代替appendChild,避开循环引用。详细见http://birdshome.cnblogs.com/archive/2005/02/16/104967.html中的讨论贴。
Cross-Page Leaks
Cross-Page Leaks和下一节提到的Pseudo-Leaks在我看来,就是IE的bug, 虽然MS死皮赖脸不承认:)
大家可以看看这段例子代码:
< html > < head > < script language = " JScript " > function LeakMemory() // 这个函数会引发Cross-Page Leaks { var hostElement = document.getElementById( " hostElement " ); // Do it a lot, look at Task Manager for memory response for (i = 0 ; i < 5000 ; i ++ ) { var parentDiv = document.createElement( " <div onClick='foo()'> " ); var childDiv = document.createElement( " <div onClick='foo()'> " ); // This will leak a temporary object parentDiv.appendChild(childDiv); hostElement.appendChild(parentDiv); hostElement.removeChild(parentDiv); parentDiv.removeChild(childDiv); parentDiv = null ; childDiv = null ; } hostElement = null ; } function CleanMemory() // 而这个函数不会引发Cross-Page Leaks { var hostElement = document.getElementById( " hostElement " ); // Do it a lot, look at Task Manager for memory response for (i = 0 ; i < 5000 ; i ++ ) { var parentDiv = document.createElement( " <div onClick='foo()'> " ); var childDiv = document.createElement( " <div onClick='foo()'> " ); // Changing the order is important, this won't leak hostElement.appendChild(parentDiv); parentDiv.appendChild(childDiv); hostElement.removeChild(parentDiv); parentDiv.removeChild(childDiv); parentDiv = null ; childDiv = null ; } hostElement = null ; } </ script > </ head > < body > < button onclick = " LeakMemory() " > Memory Leaking Insert </ button > < button onclick = " CleanMemory() " > Clean Insert </ button > < div id = " hostElement " ></ div > </ body > </ html >
LeakMemory和CleanMemory这两段函数的唯一区别就在于他们的代码的循序,从代码上看,两段代码的逻辑都没有错。
但LeakMemory却会造成泄露。原因是LeakMemory()会先建立起parentDiv和childDiv之间的连接,这时候,为了让 childDiv能够获知parentDiv的信息,因此IE需要先建立一个临时的scope对象。而后parentDiv建立了和 hostElement对象的联系,parentDiv和childDiv直接使用页面document的scope。可惜的是,IE不会释放刚才那个临 时的scope对象的内存空间,直到我们跳转页面,这块空间才能被释放。而CleanMemory函数不同,他先把parentDiv和 hostElement建立联系,而后再把childDiv和parentDiv建立联系,这个过程不需要单独建立临时的scope,只要直接使用页面 document的scope就可以了, 所以也就不会造成内存泄露了
详细原因,大家可以看看http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp这篇文章。
btw:
IE 6中垃圾回收算法,就是从那些直接"in scope"的对象开始进行mark清除的:
Every variable which is "in scope" is called a "scavenger". A scavenger may refer to a number, an object, a string, whatever. We maintain a list of scavengers – variables are moved on to the scav list when they come into scope and off the scav list when they go out of scope.
Pseudo-Leaks
这个被称为“秀逗泄露”真是恰当啊:)
看看这个例子:
< html > < head > < script language = " JScript " > function LeakMemory() { // Do it a lot, look at Task Manager for memory response for (i = 0 ; i < 5000 ; i ++ ) { hostElement.text = " function foo() { } " ;//看内存会不断增加 } } </ script > </ head > < body > < button onclick = " LeakMemory() " > Memory Leaking Insert </ button > < script id = " hostElement " > function foo() { } </ script > </ body > </ html >
MS是这么解释的,这不是内存泄漏。如果您创建了许多无法获得也无法释放的对象,那才是内存泄漏。在这里,您将创建许多元素,Internet Explorer 需要保存它们以正确呈现页面。Internet Explorer 并不知道您以后不会运行操纵您刚刚创建的所有这些对象的脚本。当页面消失时(当您浏览完,离开浏览器时)会释放内存。它不会泄漏。当销毁页面时,会中断循 环引用。
唉~~~
详细原因,大家可以看看http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp这篇文章。
其它一些琐碎的注意点
变量定义一定要用var,否则隐式声明出来的变量都是全局变量,不是局部变量;
全局变量没用时记得要置null;
注意正确使用delete,删除没用的一些函数属性;
注意正确使用try...cache,确保去处无效引用的代码能被正确执行;
open出来的窗口即使close了,它的window对象还是存在的,要记得删除引用;
frame和iframe的情况和窗口的情况类似。
参考资料
http://jibbering.com/faq/faq_notes/closures.html
http://javascript.weblogsinc.com/2005/03/07/javascript-memory-leaks/
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp
http://72.14.203.104/search?q=cache:V9Bt4_HBzQ8J:jgwebber.blogspot.com/2005/01/dhtml-leaks-like-sieve.html+DHTML+Leaks+Like+a+Sieve+&hl=zh-CN&ct=clnk&cd=9 (这是DHTML Leaks Like a Sieve)一文在google上的cache,原文已经连不上了)
http://spaces.msn.com/siteexperts/Blog/cns!1pNcL8JwTfkkjv4gg6LkVCpw!338.entry
http://support.microsoft.com/default.aspx?scid=KB;EN-US;830555
http://www.ajaxtopics.com/leakpatterns.html
http://blogs.msdn.com/ericlippert/archive/2003/09/17/53028.aspx
http://www.quirksmode.org/blog/archives/2005/02/javascript_memo.html
http://youngpup.net/2005/0221010713
http://blogs.msdn.com/ericlippert/archive/2003/09/17/53038.aspx =
http://support.microsoft.com/kb/266071/EN-US ==>IE 5.0至5.5一些版本中的GC bug
http://www.quirksmode.org/blog/archives/2006/04/ie_7_and_javasc.html ==>ie 7的改进
http://erik.eae.net/archives/2006/04/26/23.23.02/ ==>ie 7的改进
http://www.feedbackarchive.com/spamvampire/today.html ==> Try this script for memory leaks - it leaked 50 megabytes in 15 minutes with firefox on linux:
http://birdshome.cnblogs.com/archive/2005/02/15/104599.html
http://www.quirksmode.org/dom/innerhtml.html
http://www.crockford.com/javascript/memory/leak.html
《JavaScript: The Definitive Guide》4th Edition
http://outofhanwell.com/ieleak/index.php?title=Main_Page
发表评论
-
gradle编译错误:Could not find method compile() for arguments
2020-09-19 10:50 18500编译(IDEA+Gradle)一个别人的工程,出现一个 ... -
netty心跳检查之UDP篇
2019-09-15 08:50 2393部分UDP通信场景中,需要客户端定期发送心跳信息,以获取终 ... -
解决tomcat部署两个SpringBoot应用提示InstanceAlreadyExistsException
2019-06-30 11:49 3388两个SpringBoot应用部署在一个Tomcat中,单独 ... -
Eclipse配置MyBatis代码自动化功能
2019-06-29 10:16 17701.安装插件 Eclipse中,Help->Ecli ... -
vue.js中使用qrcode生成二维码
2019-05-20 00:00 7654一、安装包 npm install qrcodejs2 --s ... -
MySQL插入数据报错: Incorrect string value: '\xFD\xDE'
2019-03-31 23:19 1251我MySQL数据库用的uft-8字符集,插入数据一直很正常 ... -
vue自定义组件并双向绑定属性
2019-03-08 22:46 3258做了两个子组件,原理基本一样,一个是使用原生的select ... -
vue-router简单示例
2019-03-05 00:32 1152写个基本完整、稍有借鉴意义的示例,防止自己忘记。 &l ... -
“联通充值系统繁忙”轻松应对
2019-02-06 11:03 3973大过年的,联通充个值一直报“充值系统繁忙”。昨天晚上试了几 ... -
electron.js数据库应用---导航菜单(element-ui+mysql)
2019-02-05 21:33 2364一、环境搭建 略, ... -
electron.js数据库应用---入门(mysql+element-ui)
2019-01-27 23:19 7496我的机器:Windows10,64 ... -
SpringMVC 在controller层中注入成员变量request,是否线程安全
2018-12-17 21:17 2748@RestController public class ... -
VueJS 组件参数名命名与组件属性转化
2018-12-03 00:00 2075转自:https://www.cnblogs.com/meiy ... -
vue-resource拦截器实现token发送及检验自动化
2018-11-16 22:38 3077用了很长时间vue-resource,最近思考$http发 ... -
element-ui试用手记
2018-10-29 20:25 1745element-ui、iviewui都以vue.js为基础 ... -
iviewui中表格控件中render的使用示例
2018-07-07 16:46 9786示例了如何在表格中显示按钮,如何将代码转化为文字。 i ... -
Tomcat错误“Alias name tomcat does not identify a key entry”解决
2018-07-05 21:39 6571申请到了阿里云的证书后,下载、按照说明生成jks格式证书、 ... -
阿里云免费证书“fileauth.txt内容配置错误”解决
2018-07-05 20:43 5299最近研究微信小程序开发,上阿里云申请了个证书,使用文件验证 ... -
springboot2.0跨域配置
2018-07-04 22:11 5285springboot2.0跨域配置: 一、代码 ... -
微信小程序使用code换openid的方法(JAVA、SpringBoot)
2018-07-01 21:52 10398微信小程序序的代码中提示,使用code换取openid,但 ...
相关推荐
【JavaScript源代码】一篇文章弄懂javascript内存泄漏 在JavaScript中,内存管理对于程序性能至关重要,因为内存泄漏会导致程序效率下降,甚至可能导致应用崩溃。本文旨在深入解析JavaScript中的内存泄漏及其解决...
VBScript & DHTML 脚本技术讨论版 - 无忧脚本 ---体验编写HTML代码的乐趣 - 51JS_COM_files对JavaScript调用堆栈和setTimeout用法的深入研究 - Felix Woo_files关于Javascript的内存泄漏问题的整理稿 - tim-wu - ...
在阅读了题目为《唯快不破——高效定位线上Node.js应用内存泄漏》的文档内容之后,我们可以提炼出以下关于Node.js应用性能优化和内存泄漏定位的知识点。 首先,文档提到了Node.js应用的定位环境,这包括Node.js应用...
JavaScript 使用自动垃圾回收机制来处理不再需要的对象,避免内存泄漏。 #### 四、GC算法介绍 1. **引用计数算法**: - **原理**:通过跟踪每个对象被引用的次数来确定是否可以回收该对象。 - **优点**:实现...
内存泄露是计算机科学中的一个重要概念,尤其在开发单页应用(SPA)如Vue.js应用时,这个问题尤为突出。内存泄露是指系统进程不再使用的内存没有得到释放,导致内存占用越来越多,最终影响系统性能,甚至造成程序...
### JavaScript的垃圾回收机制详解 #### 一、为什么需要垃圾回收(GC) ...虽然大多数时候垃圾回收机制是透明地运行于后台,但了解其工作原理有助于开发者避免常见的内存泄漏问题,提高程序的整体性能。
清空数组时,应避免使用 `list = []`,因为它会改变数组引用,可能导致内存泄漏。推荐使用 `list.length = 0`,它会删除数组的所有元素,但不改变数组引用。 ### 4. 随机排序数组 要对数组进行随机排序,可以使用...
7. **内存泄漏**:虽然JavaScript有垃圾回收机制,但开发者仍需关注潜在的内存泄漏问题,如闭包、全局变量过度使用、事件监听器未正确移除等。 理解JavaScript的垃圾回收机制有助于编写更高效的代码,避免不必要的...
9. **性能优化**:了解如何避免内存泄漏,优化代码执行速度,以及利用Promise和async/await进行异步控制,都是提升JavaScript应用性能的关键。 10. **框架和库**:JavaScript有许多流行的框架和库,如React、Vue、...
4. **内存管理**:闭包中的变量会持续存在于内存中,直到不再被任何闭包引用为止,这可能会导致内存泄漏问题。 ##### 1.3 理解闭包 为了更好地理解闭包的概念,我们可以通过一个简单的例子来说明: ```javascript...
闭包的特性使得它在JavaScript开发中非常有用,但同时也需注意闭包使用不当可能导致的内存泄漏问题。 六、对象拷贝与赋值 对象的拷贝分为浅拷贝和深拷贝。浅拷贝仅复制对象的第一层属性,而深拷贝则会递归复制对象...
一是服务端进行了大量将数据转化为html标签的操作,并且由于要生成最终呈现的html标签,数据的整理操作也必须在服务端进行,这些操作大大增加了服务端负载,并且很可能由于程序出错导致服务端内存泄露。 二是由于要...
13. **性能优化**:了解如何编写高效的JavaScript代码,避免内存泄漏和提高页面加载速度。 这份源码大全将通过实例帮助开发者更好地掌握JavaScript的实际运用,从而创建出更丰富、更具交互性的动态网页。无论是初学...
理解闭包和作用域链的关系,以及如何防止内存泄漏,对编写高效代码至关重要。 7. **函数式编程**:JavaScript支持函数式编程范式,如高阶函数、柯里化、函数组合等。学习函数式编程可以帮助写出更简洁、可读性更强...
垃圾回收的主要目标是解决内存泄漏问题,即程序中不再使用的内存没有被正确释放。内存泄漏可能导致应用程序变得缓慢甚至崩溃。 ### 1. 垃圾回收算法 #### (1) 标记清理(Mark-and-Sweep) - **步骤**: - 当变量...
V8垃圾回收机制是JavaScript引擎中的核心组成部分,它负责管理程序运行时的内存,确保内存的有效利用和避免内存泄漏。以下是对V8垃圾回收机制的详细说明: 1. **JavaScript数据存储**: JavaScript的数据类型包括7...
在V8引擎中,垃圾回收采用了多种算法,如标记清除、复制算法、标记整理等,以有效地管理内存,防止内存泄漏。 了解JavaScript的内存机制对于优化代码性能和避免内存问题至关重要。例如,通过合理使用引用和深拷贝,...
- 注意管理JavaScript内存,避免因过多的DWR调用导致内存泄漏。 - 使用AJAX调用时,确保考虑页面状态和用户交互,避免造成混乱。 理解并掌握以上DWR开发步骤,你就能有效地利用DWR创建高性能、互动性强的Web应用...
内存泄漏是Node.js应用程序中常见的问题,可能导致服务器响应变慢甚至崩溃。当遇到这种情况时,可以暂时通过增大堆内存限制(使用`--max-old-space-size`参数)来缓解问题,但这只是临时解决方案,最终需要找到并...
6. **代码分析**:通过静态分析技术找出潜在的错误或性能瓶颈,如空指针引用、内存泄漏等。 常见的C语言代码整理工具有很多,例如: - **Clang Format**:由LLVM项目开发,支持多种格式化风格,可与各种集成开发...