解决方案
成都创新互联网站建设由有经验的网站设计师、开发人员和项目经理组成的专业建站团队,负责网站视觉设计、用户体验优化、交互设计和前端开发等方面的工作,以确保网站外观精美、网站制作、成都网站设计易于使用并且具有良好的响应性。
这事做的方式jQuery的AJAX方法之一:
一个。创建循环引用,IE浏览器尤其是坏
乙。创建在其上不能由于它们已被创建的方式和DontDelete属性的设置中删除内部对象的属性。更多信息请参见本:一href=""
无论哪种方式,该垃圾收集器将是从拾取垃圾pvented $ P $,这将导致失控内存泄漏,尤其是如果该可疑的功能被频繁执行。
[img]删除节点的函数
function removeNode(n){
if(n n.tagName != 'BODY'){
jQuery.event.remove(n);
jQuery.removeData(n);
for(var i=0,e;e=n.childNodes[i++];){
removeNode(e);}
d = d || document.createElement('div');
d.appendChild(n);
d.innerHTML = '';
//d.outerHTML = '';}}调用部分:
function temp() {
$.get(url, null, function(data) {
if(data['success']) {
$('#scrollZJ01').children().each(function(i){
removeNode(this);});document.getElementById("scrollZJ01").innerHTML = "";//显示数据var innerHtml = "";
for(var i =0;i data["pickedDtails"].length;i++){
innerHtml+="li";
innerHtml+="span"+data["pickedDtails"][i]["luckyAt"]+"/span";
innerHtml+="/span";
innerHtml+="/li";}document.getElementById("scrollZJ01").innerHTML = innerHtml;}dom中的节点数不增长,但是内存一直在增加,每次200k左右
你这种情况就不应该用轮询,而应该在ajax的回调函数(最好是complete)中再次发起下一次请求,这样就可以保证每次请求都是在上一次请求结束后才发起的,这样就不会造成崩溃了。比如:
function xxx(){
$.ajax({
url:"......",
data:{......},
success:function(data){
//处理返回数据
},
error:function(){
//处理错误
},
complete:function(){ //不管成功与失败,都会发生complete回调
setTimeout(xxx,5000); //5秒后再次发起ajax请求
//也可以直接用 xxx(); 可以做到完全实时,但会牺牲一些性能
}
});
}
特别注意,xxx函数在外部调用时,不能再用 setInterval,而应该是xxx()直接调用!
存泄漏可以定义为一个应用,由于某些原因不再需要的内存没有被操作系统或者空闲内存池回收。编程语言支持多种管理内存的方式。这些方式可能会减少内存泄漏的几率。然而,某一块内存是否没有用到实际上是一个不可判定的问题。换句话说,只有开发者可以弄清一块内存是否可以被操作系统回收。某些编程语言提供了帮助开发者做这个的特性。其他一些语言期望开发者可以完全明确什么时候一块内存是没被使用的。
1.意外的全局变量
JavaScript的目标是开发一种看起来像Java但足够自由的被初学者使用的语言。JavaScript自由的其中一种方式是它可以处理没有声明的变量:一个未声明的变量的引用在全局对象中创建了一个新变量。在浏览器的环境中,全局对象是window。也就是说:
123
function foo(arg) {bar = "this is a hidden global variable";}
实际上是:
123
function foo(arg) {window.bar = "this is an explicit global variable";}
如果bar是仅在foo函数作用域内承载引用,并且你忘记用var来声明的变量,一个意外的全局变量就被创建了。在这个例子中,泄漏一个单一字符串不会有太大害处,但这的确是不好的。
另一种意外全局变量被创建的方式是通过this:
1234567
function foo() {this.variable = "potential accidental global";}// Foo called on its own, this points to the global object (window)// rather than being undefined.foo();
为了阻止这种错误发生,在你的Javascript文件最前面添加'use strict;'。这开启了解析JavaScript的阻止意外全局的更严格的模式。
全局变量的一个注意事项:
即使我们谈了不明的全局变量,仍然存在很多代码被显式的全局变量填充的情况。这是通过定义不可收集的情况(除非清零或重新赋值)。特别的,用来临时存储和处理大量信息的全局变量会引起关注。如果必须用全局变量来存储很多数据,在处理完之后,确保对其清零或重新赋值。 一个在与全局连接上增加内存消耗常见的原因是缓存)。 缓存存储重复被使用的数据。为此,为了有效,缓存必须有其大小的上限。飙出限制的缓存可能会因为内容不可被回收,导致高内存消耗。
2.被遗忘的计时器或回调
在JavaScript中setInterval的使用相当常见。其他库提供观察者和其他工具以回调。这些库中大多数,在引用的实例变成不可访问之后,负责让回调的任何引用也不可访问。在setInterval的情况下,这样的代码很常见:
12345678
var someResource = getData();setInterval(function() {var node = document.getElementById('Node');if(node) {// Do stuff with node and someResource.node.innerHTML = JSON.stringify(someResource));}}, 1000);
这个例子表明了跳动的计时器可能发生什么:计时器使得节点或数据的引用不再被需要了。代表node的对象将来可能被移除,使得整个块在间隔中的处理不必要。然而,处理函数,由于间隔仍然是活跃的,不能被回收(间隔需要被停掉才能回收)。如果间隔处理不能被回收,它的依赖也不能被回收。那意味着可能存储着大量数据的someResource,也不能被回收。
观察者情况下,一旦不被需要(或相关的对象快要访问不到)就创建明确移除他们的函数很重要。在过去,这由于特定浏览器(IE6)不能很好的管理循环引用(下面有更多相关信息),曾经尤为重要。现如今,一旦观察对象变成不可访问的,即使收听者没有明确的被移除,多数浏览器可以并会回收观察者处理函数。然而,它保持了在对象被处理前明确的移除这些观察者的好实践。例如:
12345678910111213
var element = document.getElementById('button');function onClick(event) {element.innerHtml = 'text';}element.addEventListener('click', onClick);// Do stuffelement.removeEventListener('click', onClick);element.parentNode.removeChild(element);// Now when element goes out of scope,// both element and onClick will be collected even in old browsers that don't// handle cycles well.
一条关于对象观察者及循环引用的笔记
观察者和循环引用曾经是JavaScript开发者的祸患。这是由于IE垃圾回收的一个bug(或者设计决议)出现的情况。IE的老版本不能检测到DOM节点和JavaScript代码间的循环引用。 这是一个通常为观察到的保留引用(如同上面的例子)的观察者的典型。 也就是说,每次在IE中对一个节点添加观察者的时候,会导致泄漏。这是开发者在节点或空引用之前开始明确的移除处理函数的原因。 现在,现代浏览器(包括IE和MS Edge)使用可以剪裁这些循环和正确处理的现代垃圾回收算法。换言之,在使一个节点不可访问前,调用removeEventLister不是严格意义上必须的。
像Jquery一样的框架和库做了在处置一个节点前(当为其使用特定的API的时候)移除监听者的工作。这被在库内部处理,即使在像老版本IE一样有问题的浏览器里面跑,也会确保没有泄漏产生。
3. 超出DOM引用
有时存储DOM节点到数据结构中可能有用。假设你想要迅速的更新一个表格几行内容。存储每个DOM行节点的引用到一个字典或数组会起作用。当这发生是,两个对于同个DOM元素的引用被留存:一个在DOM树中,另外一个在字典中。如果在将来的某些点你决定要移除这些行,需要让两个引用都不可用。
123456789101112131415161718192021
var elements = {button: document.getElementById('button'),image: document.getElementById('image'),text: document.getElementById('text')};function doStuff() {image.src = '';button.click();console.log(text.innerHTML);// Much more logic}function removeButton() {// The button is a direct child of body.document.body.removeChild(document.getElementById('button'));// At this point, we still have a reference to #button in the global// elements dictionary. In other words, the button element is still in// memory and cannot be collected by the GC.}
对此的额外考虑,必须处理DOM树内的内部节点或叶子节点。假设你在JavaScript代码中保留了一个对于特定的表格内节点(一个td标签)的引用。在将来的某个点决定从DOM中移除这个表格,但是保留对于那个节点的引用。直观的,会假设GC会回收除那个节点之外的每个节点。在实践中,这不会发生的:这个单节点是那个表格的子节点,子节点保留对父节点引用。换句话说,来自JavaScript代码的表格元素的引用会引起在内存里存整个表格。当保留DOM元素的引用的时候,仔细考虑下。
4.闭包
一个JavaScript开发的关键点是闭包:从父级作用域捕获变量的匿名函数。很多开发者发现,由于JavaScript runtime的实现细节,有以一种微妙的方式泄漏的可能,这种特殊的情况:
123456789101112131415
var theThing = null;var replaceThing = function () {var originalThing = theThing;var unused = function () {if (originalThing)console.log("hi");};theThing = {longStr: new Array(1000000).join('*'),someMethod: function () {console.log(someMessage);}};};setInterval(replaceThing, 1000);
这个代码片段做了一件事:每次replaceThing被调用的时候,theThing获取到一个包括一个大数组和新闭包(somMethod)的新对象。同时,变量unused保留了一个有originalThing(theThing从之前的对replaceThing的调用)引用的闭包。已经有点疑惑了,哈?重要的是一旦一个作用域被在同个父作用域下的闭包创建,那个作用域是共享的。这种情况下,为闭包somMethod创建的作用域被unused共享了。unused有一个对originalThing的引用。即使unused从来没被用过,someMethod可以通过theTing被使用。由于someMethod和unused共享了闭包作用域,即使unused从来没被用过,它对originalThing的引用迫使它停留在活跃状态(不能回收)。当这个代码片段重复运行的时候,可以看到内存使用稳步的增长。GC运行的时候,这并不会减轻。本质上,一组关联的闭包被创建(同unused变量在表单中的根节点一起),这些闭包作用域中每个带了大数组一个非直接的引用,导致了大型的泄漏。
jquery 就是一堆操作元素的js脚本封装。
因此 jquery 的内存回收 也就是 js的内存回收。
js的内存回收机制比较复杂,我也仅仅是做了一些基础的了解,避免内存泄漏的问题。而内存泄漏,主要是循环引用引起的。js自动对孤立的无法再次访问的变量,定时回收。基本上不用担心。
例如:jquery 插件绑定的元素,会new一个方法,关联到元素,元素删除后,与之对应的所有内存自动回收;
使用谷歌浏览器开发者工具【profiles-take heap snapshot】,可以查看当前内存进驻情况,比较两次差异,可以对比出增减了那些对象。