【问题标题】:Major JavaScript memory leak主要的 JavaScript 内存泄漏
【发布时间】:2011-04-08 14:30:26
【问题描述】:

大家!我正在开发某种活动日历,我使用 jQuery 作为前端,使用 PHP 作为后端。我有所有用 PHP 创建的日历数据,并以 JSON 编码发送到客户端。

考虑以下代码(简化):

    jQuery(document).ready(function($) {

    // property which contains calendar object 
    this.Calendar; 
    // get calendar object 
    show_month();

    /* Assign a click event to the next month button */

    $('#cal_month .next span').live('click', function() {
        var month = $(this).attr('id');
        var year  = $(this).attr('class');
        show_month(month, year);
    });

    function show_month(month, year) {
        // delete pointers to the current month object
        window.Calendar = undefined;
        // get new month object
        window.Calendar = get_month(month, year);

        /* doing some stuff with this object here, like output to the 
           document etc., no event bindings */
    }

    function get_month(month, year) {
        var calendar;
        $.ajax({
            type: 'GET',
            dataType: 'json',
            async: false,
            timeout: 100,
            url: '../some_url.php?month='+month+'&year='+year,
            success: function(result) { calendar = result; }
        });
       return calendar;
    }

    var counter = 0;
    while (counter != 1000) {
        $('#cal_month .next span').trigger('click');
        counter ++;
    } 
});

手动切换月份以及循环会导致大量内存泄漏。我在这里以及通常在互联网上阅读了很多关于内存泄漏、js 闭包等的信息,但我想我仍然有一些误解。我很高兴了解我的代码有什么问题。

更新

我正在查看任务管理器中的 firefox.exe(其他浏览器也有同样的问题)来测量内存使用情况。即使我从页面导航,内存也不会释放。一段时间后,它会导致性能大幅下降,因为我可以让它使用 600+ Mb。

我还编写了一个循环来切换月份(在上面添加了代码)。

更新 2

我使用 global 的原因是在我的事件日历中我也有周和日视图,所以我希望一个活动的月份对象可用于处理这两个视图的函数,并且只销毁它并获取新的用户切换月份时的一个。我的问题正是全局变量的使用。那个解决了,现在试图弄清楚如何在用户明确切换月份之前保持对象可用......

顺便说一句,我创建了一个 while 循环仅用于基准测试,它与我的实际代码无关。

【问题讨论】:

  • 为什么Calendar 是全局的?只需将其声明为var Calendar; 并将其在其他地方引用为Calendar 而不是window.Calendar。也无需在将 Calendar = undefined; 分配给新值之前立即分配它。
  • 我没有看到任何内存泄漏,但我可能是错的。一个示例页面(或更多代码)会很有帮助,因此我们可以对其进行测试。
  • 你究竟是如何测量内存使用的?
  • @MattBall 这是合乎逻辑的,这就是我首先写的,但效果相同,那时我开始思考指向对象的指针、垃圾收集器和其他东西,以及想出了可能更错误的决定。
  • 我想知道当您在几个月中循环时,事件处理程序是否没有被破坏。我发现了这个 - stackoverflow.com/questions/2316726/javascript-memory-leaks ,这可能会有所帮助。

标签: javascript jquery json memory-leaks closures


【解决方案1】:

我很想知道您为什么认为存在内存泄漏问题。我发现还有两个与内存无关但可能更重要的大问题。

第一个问题是同步服务器调用。您原则上应该从不使用同步调用,因为它会在请求进行时锁定浏览器。 编辑:在该循环中执行此操作 1000 次将锁定浏览器长达 1000 * 100 毫秒,这将导致一些(容我们说)用户体验问题。

Second 是全局日历对象。除了依赖于令人困惑的全局状态之外,您还无法做一些简单的事情,例如在同一页面上有 2 个日历。

下面的代码解决了这两个问题。

jQuery(document).ready(function($) {

    $('#cal_month .next span').live('click', function() {
        var month = $(this).attr('id');
        var year  = $(this).attr('class');
        generate_calendar(month, year);
    });

    generate_calendar();

    function calendar_fetch_complete(result) {
        var calendar = result;

        /* doing some stuff with this object here, like output to the 
           document etc.*/
    }

    function generate_calendar(_month, _year) {
        var month = _month || (new Date().getMonth() + 1),
            year  = _year  || (new Date().getYear() + 1900);
        $.ajax({
            type: 'GET',
            dataType: 'json',
            url: '../some_url.php?month='+month+'&year='+year,
            success: calendar_fetch_complete
        });
    }

});

【讨论】:

    【解决方案2】:

    我会建议使用像 http://www.dynatrace.com/en/ 这样的工具,它们有时真的很有帮助。

    查看这篇来自 John Resig 本人的文章 http://ejohn.org/blog/deep-tracing-of-internet-explorer/

    试试下面的萤火虫技巧: 我建议你再尝试一件事。简单的萤火虫技巧。当您不在 UI 控件上使用/鼠标操作时,只需单击萤火虫的分析按钮。看看有多少函数和调用发生了,看看有没有奇怪的东西,需要很长时间。这是一个很好的简单技巧,但有助于解决这些问题...... :)

    http://getfirebug.com/logging

    Understanding Firebug profiler output

    【讨论】:

      【解决方案3】:
      var counter = 0;
      while (counter != 1000) {
          $('#cal_month .next span').trigger('click');
          counter ++;
      } 
      

      什么?根据此代码,您将触发多个 span 元素 1000 次,并为这些元素中的每一个请求同步 JSON 1000 次,这会重写单个全局变量。这不是内存“泄漏”,而是耗尽。

      我建议重构您的代码以包含异步请求并移除该 while 循环。

      【讨论】:

        【解决方案4】:

        您说存在内存泄漏,但您如何确定这一点?

        您可能只是在查看浏览器进程的内存使用情况。浏览器对内存所做的任何事情都不一定与您在 javascript 中所做的事情有关。可能是 javascript 引擎没有释放它认为会再次使用的内存空间——无论您当前是否正在使用它。

        请找到合适的工具来分析此问题和/或提供更多信息,说明您认为存在内存泄漏的原因。

        【讨论】:

        • 感谢您的回答,或许您可以给个建议,这是一个很好用的工具。
        • @noname:我只需要各种浏览器中的调试工具。除此之外,我没有任何建议。
        【解决方案5】:

        而(计数器!= 1000){ $('#cal_month .next span').trigger('click'); 计数器++; }

        这看起来您正在为某事分配 1000 个触发器 - 您不能处理来自父对象的任何点击吗?

        【讨论】:

          猜你喜欢
          • 2011-02-28
          • 2020-08-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-09-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多