JavaScript 对象何时销毁

When are JavaScript objects destroyed?

本文关键字:何时销 对象 JavaScript      更新时间:2023-09-26

C++我可以显式定义构造函数和析构函数,然后在构造函数/析构函数中从 with 中<<"C 或 D 调用",以确切知道位置。

但是在 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();
    }
};

这种认为对象销毁可以简化为内存垃圾回收的想法在我看来是危险的误导,因为问题不能简化为释放内存。

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

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

处理此问题的最佳方法是,如果模块需要使用析构函数,请适当地记录模块,并强调无法使用此类内容的资源泄漏情况。

编辑 2020:@BuffyG的这个答案比我在下面的旧答案更准确和有用。对象销毁不仅仅是内存泄漏,现代 JavaScript 没有我提到的模式。

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

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

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

"垃圾回收器如何知道何时可以为对象释放内存"

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

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

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

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

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

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

这将设置一个自动消除的超时,该超时在当前 JavaScript 脚本完成(并且主事件循环恢复)时完成。

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

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

是否可以在javascript中创建"弱引用"?

其中讨论的策略是"削弱"A和B之间的引用之一,以便垃圾收集者知道它可以被破坏,从而导致他们最终被收获......或者可能在内存不足的情况下被盗

当然,也可以从纪律中受益。 如果您知道不再使用某些内容,请编写一个例程,将其各种引用字段设置为 Null,然后再将其丢弃到垃圾回收器......"整理好。"


JavaScript 中的垃圾收集策略自最早的实现以来已经有了长足的进步,因为该语言变得如此重要。 当您学习有关此主题的文本时,请确保它们是最新的。