【问题标题】:When are JavaScript objects destroyed?JavaScript 对象何时被销毁?
【发布时间】:2012-04-24 03:43:45
【问题描述】:

在 C++ 中,我可以显式定义构造函数和析构函数,然后在构造函数/析构函数中 cout

但是在 JavaScript 中,我如何知道对象何时被破坏。下面的例子就是我关心的情况。

我在超时时调用一个内部函数,我想知道只要计时器运行,对象是否还活着,等待再次调用下一个。

用户点击调用控制

// Calls  Control

控制调用消息

var message_object = new Message( response_element );

消息调用效果

new Effects().fade( this.element, 'down', 4000 );
message_object.display( 'empty' );

效果

/**
 *Effects - build out as needed
 *  element - holds the element to fade
 *  direction - determines which way to fade the element
 *  max_time - length of the fade
 */

var Effects = function(  ) 
{
    this.fade = function( element, direction, max_time ) 
    {
        element.elapsed = 0;
        clearTimeout( element.timeout_id );
        function next() 
        {
            element.elapsed += 10;
            if ( direction === 'up' )
            {
                element.style.opacity = element.elapsed / max_time;
            }
            else if ( direction === 'down' )
            {
                element.style.opacity = ( max_time - element.elapsed ) / max_time;
            }
            if ( element.elapsed <= max_time ) 
            {
                element.timeout_id = setTimeout( next, 10 );
            }
        }
        next();
    }
};

【问题讨论】:

  • JavaScript 垃圾收集 - stackoverflow.com/q/864516/402706
  • 一般情况下是的,有关解除分配对象的具体条件的讨论,请参见上面的链接。
  • 您担心哪个对象的寿命?
  • 不,你的想法正好相反。 Control 有对 Message 的引用,但不一定是相反的。除非 Effects 有某种访问 Message 的方式——除非 Message 调用它或将对自身的引用传递给它,否则它不会—— Message 消失。是的,this.element 仍然存在,但它周围的对象消失了。

标签: javascript


【解决方案1】:

Edit 2020:This answer from @BuffyG 比我下面的旧答案更准确、更有用。对象销毁不仅仅是内存泄漏,现代 JavaScript 没有我提到的模式。

JS 对象本身没有析构函数。

JavaScript 对象(和原语)在变得不可访问时被垃圾回收,这意味着在当前执行上下文中不可能引用它们。 JavaScript 运行时必须为此持续监控。因此,除非您使用 delete 关键字来删除某些东西,否则它的破坏就在幕后。一些浏览器不擅长检测留在闭包范围内的引用(我在看着你,Redmond),这就是为什么你经常看到在函数结束时将对象设置为 null 的原因——以确保在 IE 中释放内存。

【讨论】:

  • JS 对象在 变得不可访问之后被 GC(你无法控制何时)。在 C++ 中,对象在变得不可访问时被销毁。
  • @Gabe 在 C++ 中,当您显式删除它们时,对象会被销毁,无论它们是否可以在其他地方访问(实际上,从技术上讲,它们必须是可访问的删除它们)。它们不会在(或之后)变得不可访问时自动销毁。
  • @JasonC:抱歉,我说的是 C++ 的“自动”内存管理,包括 RAII、autoptr 等。
  • @JasonC 如果你不使用new(就像任何理智的 C++ 程序员一样),它们就是这样。见stackoverflow.com/questions/388242/…
【解决方案2】:

对象销毁可以简化为内存垃圾回收的概念让我觉得很危险,因为这个问题不能简化为释放内存。

析构函数负责释放其他资源,例如文件描述符或事件侦听器,垃圾回收不会自动处理这些资源。在这种情况下,绝对需要析构函数在释放内存之前展开状态,否则会泄漏资源。

在这种情况下,析构函数不是一流的概念是一个问题,无论是需要显式调用还是在对象无法访问后隐式调用它们。

处理此问题的最佳方法是在模块需要使用析构函数时适当地记录它们,并强调无法使用这种方法的资源泄漏情况。

【讨论】:

  • 这是一个非常重要的答案。从字面上看,每一个对 javascript 销毁的引用都围绕着内存管理,它根本不应该这样做。我想把这个投票给 google 的字体页面,用于 javascript 销毁。
  • 比我小时候过于自信时的回答要好得多。
【解决方案3】:

ECMAscript 中根本没有动态内存管理。垃圾收集器将处理脚本中需要内存的任何内容。所以实际上这个问题应该更像,

“垃圾收集器如何知道它何时可以为对象释放内存”

简单来说,大多数 GC 都会查看是否有任何活动引用。这可能是由于父上下文对象、原型链或对给定对象的任何直接访问。在您的特定实例中,无论何时执行setTimeout,它都会调用next(),它关闭.fade() 父上下文,而.face() 函数又持有Effects 函数(上下文)的闭包。

这意味着,只要有对 setTimeout 的调用,整个构造就会保存在内存中。

您有时可以通过nulling 变量-/对它的引用来帮助旧的 GC 实现,它能够更早或根本收集一些东西,但是现代实现对这些东西非常聪明。您实际上不必关心诸如“对象/引用的生存时间”之类的事情。

【讨论】:

  • 垃圾收集很昂贵,因此解释器通常“懒惰”地实际执行它。在垃圾收集器最终运行之前,被遗弃的数据可能会在内存中存在相当长的一段时间。当它运行时,它会“触及”大量数据,因此可能会导致许多页面错误,这些页面错误必须由操作系统的虚拟内存管理器处理。 (不同的实现采用不同的方法来减轻这种副作用。)
【解决方案4】:

我熟悉大约 8 种不同的常用编程语言。来自 C++ 环境,您会发现除了 C++ 之外几乎没有其他语言能够正确使用析构函数。第一个缺陷(从 C++ 的角度来看)是破坏被认为仅与内存有关。无法执行用户定义的功能,例如关闭文件句柄或终止网络连接作为破坏的一部分。一些语言确实允许您编写自定义析构函数,但它们有第二个失败,即它们不会在对象超出范围时执行析构函数。只要运行时方便,他们就会花时间处理它。这使得它们在某些情况下无法使用,例如释放多线程锁或自动关闭对话框,或者可能获取当前微秒时间戳来测量函数执行时间,无论函数如何退出。但是,您只需要意识到这一点并接受这些限制,并希望该语言的其他不错的功能可以弥补。

【讨论】:

    【解决方案5】:

    有一个实验性的 Firefox 和 Chrome 功能 window.requestIdleCallback() 在浏览器空闲时回调。这可以用来模拟类实例析构函数。

    从下面的代码可以得到几乎相同的效果:

    setTimeout(function()
        {
        // Simulate destructor here
        },0);
    

    这会设置一个在当前 JavaScript 脚本完成(并且主事件循环继续)时完成的自动关闭超时。

    【讨论】:

      【解决方案6】:

      另一个重要的考虑因素是数据结构中的循环引用:“A 引用 B,B 引用 A,并且没有人再引用它们中的任何一个。”从理论上讲,这可能会导致 A 和 B 都被视为无法收集,从而导致内存泄漏。

      这里已经讨论过这个主题,并有一些相当近期的更新:

      Is it possible to create a "weak reference" in javascript?

      其中讨论的策略是“削弱” A 和 B 之间的引用之一,以便垃圾收集器知道它可以被破坏,从而导致它们最终被收割......或者可能被盗 em> 内存不足。

      当然,也可以从纪律中受益。如果您知道自己不再使用某些东西,请编写一个例程,将其各种引用字段设置为 Null,然后再将其交给垃圾收集器……“保持整洁。”


      自从 JavaScript 变得如此重要以来,JavaScript 中的垃圾收集策略自从最早的实现以来已经有了很大的进步。当您研究有关此主题的文本时,请确保它们是最近的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-02
        • 1970-01-01
        • 2012-12-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多