JavaScript 对象何时销毁?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10112670/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 23:53:51  来源:igfitidea点击:

When are JavaScript objects destroyed?

javascript

提问by zetlen

In C++ I can define a constructor and destructor explicitly, and then cout << "C or D Called" from with in the constructor/destructor function, to know exactly where.

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

However in JavaScript how do I know when an object is destructed. The example below is the case that concerns me.

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

I'm calling an internal function on a timeout and I'm wondering if the object stays alive as long as the timer is running, waiting to call next again.

我在超时时调用内部函数,我想知道只要计时器正在运行,对象是否就保持活动状态,等待再次调用 next。

User Click calls Control

用户点击调用控制

// Calls  Control

Control calls Message

控制呼叫消息

var message_object = new Message( response_element );

Message calls Effects

消息调用效果

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

Effects

效果

/**
 *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();
    }
};

回答by zetlen

Edit 2020: This answer from @BuffyGis much more accurate and useful than my old answer below. Object destruction is about more than memory leaks, and modern JavaScript has none of the patterns I mentioned.

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

JS objects don't have destructors per se.

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

JavaScript objects (and primitives) are garbage collected when they become inaccessible, meaning when there is no possible reference to them in the current execution context. The JavaScript runtime has to continuously monitor for this. So unless you use the deletekeyword to remove something, then its destruction is sort of under the hood. Some browsers are bad at detecting references left in closure scope (I'm looking at you, Redmond) and that's why you often see objects being set to null at the end of functions--to make sure that memory is freed in IE.

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

回答by BuffyG

This notion that object destruction is reducible to garbage collection for memory strikes me as dangerously misleading, as the problem isn't reducible to freeing memory.

这种将对象销毁简化为内存垃圾收集的想法让我觉得这是一种危险的误导,因为问题不能简化为释放内存。

Destructors are responsible for releasing other resources, such as file descriptors or event listeners, which aren't dealt with automagically by garbage collection. In such cases destructors are absolutely required to unwind state before memory is released, or you will leak resources.

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

In such cases it's a problem that destructors aren't a first-class notion, whether they need to be called explicitly or can be called implicitly after an object becomes unreachable.

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

The best way to deal with this is to document your modules appropriately if they need destructors to be used and to underline resource leak scenarios failing such use.

解决这个问题的最好方法是适当地记录你的模块,如果它们需要使用析构函数,并强调这种使用失败的资源泄漏情况。

回答by jAndy

There is no dynamic memory managment in ECMAscript at all. A Garbage Collector will take care of anything that required memory in your script. So actually the question should be more like,

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

"How does the Garbage Collector know when it can free memory for objects"

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

Simply spoken, most GC's look if there are any active references. That might be due to parent context object, prototype chains or any direct access to a given object. In your particular instance, anytime setTimeoutgets executed, it'll call next()which closes over the .fade()parent context and the .face()function in turn holds a closure to the Effectsfunction( context ).

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

That means, as long as there are calls to setTimeout, that whole construct is held in memory.

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

You can help old'ish GC implementations sometimes a little bit, by nulling variables-/references to it is able to collect some stuff earlier or at all, but modern implementatios are pretty smart about this stuff. You actually don't have to care about things like "Object/Reference live times".

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

回答by Walt Howard

I'm familiar with about 8 different common programming languages. Coming from a C++ environment you will find that virtually no language except C++ gets destructors right. The first deficiency (from a C++ viewpoint) is that destruction is considered to only be about memory. Executing a user defined function such as closing a file handle or terminating a network connection as part of destruction is not possible. A few languages do let you write custom destructors but they have the second failing which is, they don't execute the destructor at the instant the object goes out of scope. They take their time about it, whenever it's convenient for the runtime. This makes them unusable in some contexts such as releasing multithread locks or automatically closing dialog boxes, or perhaps getting the current microsecond timestamp to measure function execution time, no matter how the function was exited. But, you just have to realize this and accept those limitations and hopefully the other nice features of the language compensate.

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

回答by David Spector

There is an experimental Firefox and Chrome function window.requestIdleCallback() that calls back when the browser is idle. This could be used to simulate a class instance destructor.

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

Almost the same effect can be obtained from the following code:

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

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

This sets an automatically-dismissed timeout that completes when the current JavaScript script completes (and the main event loop resumes).

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

回答by Mike Robinson

Another important consideration is circularreferences in data structures: "A refers to B, and B refers to A, and no one anymore refers to either of them." Theoretically this could cause both A and B to be seen as uncollectible, hence a memory-leak.

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

The topic has been discussed here, with some fairly recent updates:

该主题已在此处讨论,并有一些最近的更新:

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

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

The strategy therein discussed is to "weaken" one of the references between A and B so that the garbage-collector knows it can be broken, thus leading to them eventually being reaped ... or maybe stolenin an out-of-memory situation.

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

Of course it's also possible to benefit from discipline. If you know you're not going to use something anymore, write a routine that sets its various reference-fields to Nullbefore you abandon it to the garbage collector ... "Be tidy."

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



Garbage collection strategies in JavaScript have advanced considerably since their earliest implementations since the language has become so important. When you are studying texts on this topic, be sure that they are recent.

自从 JavaScript 变得如此重要以来,它们最早的实现以来,JavaScript 中的垃圾收集策略已经取得了长足的进步。当你学习关于这个主题的文本时,确保它们是最近的。