27

在 C++ 中,我可以显式定义构造函数和析构函数,然后在构造函数/析构函数中使用 cout << "C or D Called" 来确切知道在哪里。

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

5 回答 5

27

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

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

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

于 2012-04-11T19:39:54.517 回答
27

对象破坏可以简化为内存垃圾收集的想法让我觉得很危险,因为这个问题不能简化为释放内存。

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

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

处理这个问题的最好方法是在需要使用析构函数时适当地记录你的模块,并强调资源泄漏场景无法使用。

于 2017-05-20T20:42:43.990 回答
4

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

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

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

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

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

于 2012-04-11T19:40:48.667 回答
0

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

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

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

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

于 2019-01-23T15:15:31.903 回答
0

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

该主题已在此处进行了讨论,并提供了一些相当近期的更新:

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

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

当然,也可以从纪律中受益。如果你知道你不会再使用某些东西了,那么Null在你把它交给垃圾收集器之前,编写一个例程来设置它的各种引用字段…… “保持整洁。”


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

于 2020-03-19T15:29:23.773 回答