`

javascript内存泄漏

阅读更多
当一个系统不能正确的管理他的内存分配时,这个系统就存在内存泄漏,这对系统来说是一个bug。内存泄漏的现象可以有程序调用失败、执行减慢等。
微软的Internet Explorer就存在一系列的内存泄漏,其中最严重的就算是执行Jscript时产生的泄漏。当一个DOM对象包涵有一个JavaScript对象(例如一个事件处理函数)的引用,同时如果这个JavaScript对象又包涵该DOM对象,那么这个循环引用就形成了。这种结构本质上没有问题。此时,因为该DOM对象和这个事件处理函数并没有别的引用存在,那么垃圾回收器(一种自动的内存资源管理器)本应该把它们都回收点,并内存释放。JavaScript的垃圾回收器能够检测到这种循环引用,并不会对他产生困惑。但是不幸的是,IE DOM的内存并不能被Jscript所管理。他有他自己的内存管理系统,然而这套系统并不知道循环引用,使得一切都变得混乱。这就导致了,当循环引用形成的时候,内存释放工作不能完成,也就是产生了内存泄漏。长时间的内存泄漏就将产生内存的匮乏,使得浏览器因缺乏必要内存而崩溃?。
我们可以来演示一下。在第一段程序-question1中,我们将动态创建以10个为一组共计10000个的DOM元素(<span>),创建10个然后删除在创建10个,如此循环。你在运行这段程序时打开Windows任务管理器,就可以观察到页面运行时PF(虚拟内存)使用率一直保持不变。PF使用率的变化可以视为内存分配是否无效的指标。

Question1
<html>
    <head>
        <title>Queue Test 1</title>
    </head>
    <body>
        <script>
            /*global setTimeout */
            (function (limit, delay) {
                var queue = new Array(10);
                var n = 0;

                function makeSpan(n) {
                    var s = document.createElement('span');
                    document.body.appendChild(s);
                    var t = document.createTextNode(' ' + n);
                    s.appendChild(t);
                    return s;
                }

                function process(n) {
                    queue.push(makeSpan(n));
                    var s = queue.shift();
                    if (s) {
                        s.parentNode.removeChild(s);
                    }
                }

                function loop() {
                    if (n < limit) {
                        process(n);
                        n += 1;
                        setTimeout(loop, delay);
                    }
                }

                loop();
            })(10000, 10);
        </script>
    </body>
</html>

接下来我们运行第二段程序queuetest2。除了做与queuetest1相同的事情以外,它还未每个元素添加了一个点击事件响应函数。在Mozila和Opera上,虚拟PF利用率和queuetest1是一样的,但是在IE上我们可以看见由于内存泄漏而产生的每秒一兆的虚拟内存的稳定增量,通常这种泄露都不会被注意到。但是由于Ajax的日益流行,使得页面在浏览器的停留时间增长,使得问题变得常见了。
Question2
<html>
    <head><title>Queue Test 2</title>
    </head>
    <body>
        <script>
            /*global setTimeout */
            (function (limit, delay) {
                var queue = new Array(10);
                var n = 0;

                function makeSpan(n) {
                    var s = document.createElement('span');
                    document.body.appendChild(s);
                    var t = document.createTextNode(' ' + n);
                    s.appendChild(t);
                    s.onclick = function (e) {
                        s.style.backgroundColor = 'red';
                        alert(n);
                    };
                    return s;
                }

                function process(n) {
                    queue.push(makeSpan(n));
                    var s = queue.shift();
                    if (s) {
                        s.parentNode.removeChild(s);
                    }
                }

                function loop() {
                    if (n < limit) {
                        process(n);
                        n += 1;
                        setTimeout(loop, delay);
                    }
                }

                loop();
            })(10000, 10);
        </script>
    </body>
</html>

因为IE不能对循环引用进行回收,所以这个任务就落在了我们的肩上。如果我们明确的打破这个循环引用,那么IE就能够完成垃圾回收工作了。具微软的解释,引起内存泄漏的原因是闭包,然而这个结论肯定是非常错误的,并且这使得微软给开发者的建议也成了错误的建议。那么通过DOM来打破循环引用更简单,因为实际上不可能通过Jscript来实现。
当我们处理完一个元素后,我们必须通过把它所有的事件处理函数制空来达到破坏循环引用的目的。我们所需要做的就是把每个事件的处理函数设为空就可以了。我们甚至可以清理函数来完成这一工作。
清理函数将保存一份DOM元素的引用。它将循环检测这个元素的所有属性。如果发现了时间处理函数,就把它值为空。这样就破坏了循环引用,使得内存可以被回收释放。它同样也会检测该元素的子元素,打破他们的循环引用。这个清理函数,只在IE中有效果,对于Mozilla和Opera都无效。不管是用removeChild()或者是设置innerHTML属性的值,都应该在删除元素之前调用清理函数。
function purge(d) {
    var a = d.attributes, i, l, n;
    if (a) {
        l = a.length;
        for (i = 0; i < l; i += 1) {
            n = a[i].name;
            if (typeof d[n] === 'function') {
                d[n] = null;
            }
        }
    }
    a = d.childNodes;
    if (a) {
        l = a.length;
        for (i = 0; i < l; i += 1) {
            purge(d.childNodes[i]);
        }
    }
}
那么我们现在来运新第3个程序,queuetest3,在程序3里,元素在被删除之前都调用了清理函数。
Question3
<html>
    <head><title>Queue Test 3</title>
    </head>
    <body>
        <p>
            Queue Test 3 adds an event handler to each span, and removes it when
finished. See <a href="http://www.crockford.com/javascript/memory/leak.html">http://www.crockford.com/javascript/memory/leak.html</a>
        </p>
        <script>
            /*global onunload, setTimeout */
            (function (limit, delay) {
                var queue = new Array(10);
                var n = 0;

                function makeSpan(n) {
                    var s = document.createElement('span');
                    document.body.appendChild(s);
                    var t = document.createTextNode(' ' + n);
                    s.appendChild(t);
                    s.onclick = function (e) {
                        s.style.backgroundColor = 'red';
                        alert(n);
                    };
                    return s;
                }

                function purge(d) {
                    var a = d.attributes, i, l, n;
                    if (a) {
                        l = a.length;
                        for (i = 0; i < l; i += 1) {
                            n = a[i].name;
                            if (typeof d[n] === 'function') {
                                d[n] = null;
                            }
                        }
                    }
                    a = d.childNodes;
                    if (a) {
                        l = a.length;
                        for (i = 0; i < l; i += 1) {
                            purge(d.childNodes[i]);
                        }
                    }
                }

                function process(n) {
                    queue.push(makeSpan(n));
                    var s = queue.shift();
                    if (s) {
                        purge(s);
                        s.parentNode.removeChild(s);
                    }
                }

                function loop() {
                    if (n < limit) {
                        process(n);
                        n += 1;
                        setTimeout(loop, delay);
                    }
                }
                onunload = function (e) {
                    purge(document.body);
                };

                loop();
            })(10000, 10);
        </script>
    </body>
</html>

更新:微软发布了该问题的补丁:929874。如果你有十足的信心确保你所有的用户都可以获得该更新,那么你将不再需要上面的清理函数。但不幸的是,这不可能如你所愿,所以可能清理工作在IE6被淘汰之前还是有必要的。
这就是web的天性,有清理不完的bugs。
原文地址:http://feed.yeeyan.com/articles/view/3407/10103
分享到:
评论

相关推荐

    Javascript内存泄露

    ### JavaScript内存泄露详解 #### 一、什么是JavaScript内存泄露? 在JavaScript编程中,内存泄露指的是在浏览器中不再使用的变量或对象占用的内存没有被及时回收,导致可用内存逐渐减少的现象。这种现象通常发生...

    javascript内存泄露问题的解析

    JavaScript内存泄露问题的解析 JavaScript内存泄露问题是一种常见的bug,它会导致系统崩溃和性能下降。内存泄露是指系统不能正确地管理内存分配的情况,这可能会导致程序调用失败、执行减慢等问题。 在JavaScript...

    javascript 内存泄漏 检测 解决 检测工具 原因分析

    JavaScript内存泄漏是一个重要的编程问题,尤其对于Web应用来说,它可能导致性能下降,用户界面响应变慢,甚至在极端情况下导致应用程序崩溃。理解内存泄漏的原因、如何检测和解决它们是每个JavaScript开发者必备的...

    JavaScript内存泄漏的处理方式

    在探讨JavaScript内存泄漏的处理方式前,有必要了解内存泄漏的含义。内存泄漏通常指的是程序不再使用的内存未能被释放,导致内存消耗不断上升。即使在高级语言如JavaScript中,这一问题亦可能出现,尽管它拥有垃圾...

    sIEve-0.0.8-javascript内存泄漏检测工具

    sIEve是一款专门针对JavaScript内存泄漏检测的工具,版本为0.0.8。这款工具的主要目标是帮助开发者识别和定位JavaScript应用中的内存泄漏问题,以优化性能并提高用户体验。sIEve通过深入分析JavaScript运行时的内存...

    javascript 内存泄漏

    本文将详细探讨JavaScript内存泄漏的原因,并展示一些常见的内存泄漏模式,以及如何解决这些问题。 首先,JavaScript 是一种垃圾收集语言,意味着对象创建时会分配内存,在没有更多引用时由浏览器回收这些内存。...

    深入浅出JavaScript内存泄漏.doc

    JavaScript内存泄漏是一个重要的主题,尤其是在现代Web开发中,因为页面长时间保持活跃且动态更新内容的情况越来越普遍。了解和处理内存泄漏对于优化Web应用性能至关重要。本文将深入探讨JavaScript中的几种常见内存...

    【JavaScript源代码】一篇文章弄懂javascript内存泄漏.docx

    【JavaScript源代码】一篇文章弄懂javascript内存泄漏 在JavaScript中,内存管理对于程序性能至关重要,因为内存泄漏会导致程序效率下降,甚至可能导致应用崩溃。本文旨在深入解析JavaScript中的内存泄漏及其解决...

    JavaScript 内存泄露的4种方式及如何避免 – 码农网1

    常见的JavaScript内存泄露类型有: 1. 意外的全局变量:未声明的变量默认成为全局变量,这可能导致意外的内存占用。例如,忘记在函数内部使用`var`关键字会导致变量被附加到全局对象window上,形成持久化的内存占用...

    常见的JavaScript内存泄露原因及解决方案.docx

    ### 常见的JavaScript内存泄露原因及解决方案 #### 引言 在现代Web开发中,JavaScript已成为构建复杂用户界面的主要编程语言之一。随着应用程序变得越来越庞大与复杂,有效地管理和优化内存成为确保应用性能和用户...

    内存泄漏检测工具

    内存泄漏是程序运行过程中,不再使用的内存没有被正确释放,导致系统资源持续占用,从而影响程序性能甚至系统...了解并掌握这些知识点,开发者可以更有效地预防和解决JavaScript内存泄漏问题,确保应用的高效稳定运行。

    测试JavaScript在IE中的内存泄露

    2. **内存泄漏类型**:常见的JavaScript内存泄露包括全局变量、闭包引用、DOM元素引用、事件监听器等。了解这些类型有助于识别潜在问题。 3. **工具使用**:利用如IE Developer Tools(F12工具)、Chrome DevTools...

    js内存泄露问题

    JavaScript内存泄露是一个重要的性能优化话题,尤其是在...对于IE浏览器,由于其早期版本的垃圾收集机制不完善,内存泄露问题更为突出,文档《理解并解决IE的内存泄漏方式》可能会提供更具体的针对IE浏览器的解决方案。

    脚本IE内存泄露检测.rar

    标题中的“脚本IE内存泄露检测.rar”表明这是一个专门针对Internet Explorer浏览器的JavaScript内存泄漏检测工具。内存泄漏是编程中常见的问题,特别是在处理大量数据或长时间运行的网页应用时,可能导致浏览器性能...

    css样式和内存泄漏

    “常见兼容问题.doc”可能汇总了各种类型的CSS兼容和JavaScript内存泄漏问题,为开发者提供了一站式参考。而“div+css浏览器兼容问题解决方法(PDF版).pdf”很可能提供了一种系统性的解决策略,包括了从设计到实现的...

    详谈JavaScript内存泄漏

    总结来说,JavaScript内存泄漏是一个重要问题,它主要与闭包及其引起的循环引用有关。理解JavaScript的垃圾回收机制和闭包的工作原理,有助于我们编写出更安全、更高效的代码,避免不必要的内存泄漏。对于IE浏览器中...

    Js内存泄漏及解决方案.pdf

    JavaScript内存泄漏指的是由于代码的某些问题导致内存不能被垃圾回收机制正常回收,从而随着时间的推移,内存消耗持续增长。这不仅会导致程序运行缓慢,最终还可能导致程序崩溃。根据给定文件中的内容,我们可以分析...

    Iframe内存泄露分析

    检测内存泄漏的工具和手段确实有限,仅有的两个工具(JavaScript Memory LeakDetector 和 sIEve )都不太好用,不像 Java 里面的一些工具能精准定位。因此,需要通过经验预测最有可能泄漏的几个点,再通过排除法,...

Global site tag (gtag.js) - Google Analytics