27

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.

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

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.

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();
    }
};
  • 6
    JavaScript Garbage Collection - http://stackoverflow.com/q/864516/402706 – Brandon Boone Apr 11 '12 at 19:34
  • In general yes, see the above link for discussion on the specific conditions for deallocating objects. – Jakub Hampl Apr 11 '12 at 19:35
  • Which object are you worried about the lifespan of? – Phrogz Apr 11 '12 at 19:42
  • No, you're thinking in the opposite direction. Control has a reference to Message, but not necessarily the reverse. Unless Effects has some way of accessing Message -- which it doesn't unless Message invoked it or passed a reference to itself to it -- Message goes away. Yes, this.element stays, but the object around it disappears. – zetlen Apr 11 '12 at 21:11
  • See also [something like stackbased objects in c++ for javascript](http://stackoverflow.com/questions/13218199/something-like-stackbased-objects-in-c-for-javascript) – user Apr 02 '14 at 14:49

5 Answers5

28

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.

BuffyG
  • 281
  • 3
  • 2
  • 1
    This is such an important answer. Literally every reference to javascript destruction revolves around memory management, which it simply should not. I'd like to upvote this to the font page of google for javascript destruction. – Erik Aronesty Oct 26 '18 at 13:35
  • Much better than my answer from when I was an overconfident junior. – zetlen Mar 19 '20 at 15:04
27

Edit 2020: This answer from @BuffyG is 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.

JS objects don't have destructors per se.

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 delete keyword 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.

zetlen
  • 3,609
  • 25
  • 22
  • 16
    JS objects get GCed *after* they become inaccessible (you have no control over when). It's in C++ that objects are destroyed *when* they become inaccessible. – Gabe Apr 11 '12 at 19:41
  • Gabe: true, that's a good clarification. For many browsers it's simply periodic. The All Foo: They live because the timeout continues executing, and so needs references to variables in the Effects context. – zetlen Apr 11 '12 at 19:44
  • 2
    @Gabe In C++ objects are destroyed when you *explicitly* delete them, regardless of whether or not they are accessible elsewhere (in fact, technically, they must be accessible for you to delete them). They are not automatically destroyed *when* (or *after*) they become inaccessible. – Jason C Oct 12 '13 at 18:57
  • 3
    @JasonC: Sorry, I was talking about C++'s "automatic" memory management, with RAII, `autoptr`, and such. – Gabe Oct 13 '13 at 02:33
  • 3
    @JasonC They are if you don’t use `new` (like any sane C++ programmer). See http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list. –  Nov 12 '13 at 08:30
  • 1
    @rightfold That requires automatic pointers, which ultimately fall under the category of "explicitly deleting" because they are not a behind-the-scenes feature of the executor or generated code; rather they are convenient constructs also implemented in C++ (if you look at the code for e.g. `std::auto_ptr` you *will* eventually trace it to an actual explicit "delete"). So, yes, the developer using those constructs doesn't have to actually type "delete", but at some point "delete" is explicitly called. The other alternative is using the stack for objects, but that is not always possible. :) – Jason C Nov 13 '13 at 19:27
  • 2
    [`delete` does not remove anything from memory!](http://perfectionkills.com/understanding-delete/) – Bergi Jul 06 '15 at 11:52
  • Primitives are not subject to garbage collection. Having no reference in the current execution context doesn't make an object inaccessible. `delete` removes a property from an object. – a better oliver Oct 22 '15 at 12:28
  • 1
    @Bergi, if you are talking about the C++ `delete`, it does call the destructor and then `free()` to release the memory. Hence the confusion when someone comes from C++ to JavaScript... `delete` in JavaScript may release something from memory, it will depend on how the GC is programmed (i.e. with a refcount you should be able to delete the data immediately if you just deleted the last instance.) – Alexis Wilke Apr 07 '16 at 00:10
  • @AlexisWilke: No, I'm not talking about C++ (as should be clear from the linked page). And again, `delete` has nothing to do with memory in JS (or at least, not more than any other part of the language). You cannot "delete an instance". – Bergi Apr 07 '16 at 00:17
  • What versions of IE? Is this still a problem in 2017? – trysis Mar 30 '17 at 14:32
  • JavaScript objects become inaccessible when there is no reference chain to them in **any** [existing execution context](https://developer.chrome.com/devtools/docs/heap-profiling#qna), in any of the JavaScript VM threads. This also includes callback functions given to built-in async functions (in node.js), and reference chains held by them. – Orafu Nov 09 '17 at 18:58
  • Old answer and not a particularly useful addition, but it is worth noting that `WeakMap` and `WeakSet` are recent additions to the language that do not mark JS objects as "accessible", but do allow access to the objects. I have yet to run across a real usecase for either, but they do exist in case anyone happens upon here and needs them. – River Tam Apr 10 '18 at 14:19
  • I don't think the OP's question was talking about memory management. – Erik Aronesty Oct 26 '18 at 13:36
4

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,

"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 setTimeout gets executed, it'll call next() which closes over the .fade() parent context and the .face() function in turn holds a closure to the Effects function( context ).

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

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".

josh3736
  • 139,160
  • 33
  • 216
  • 263
jAndy
  • 231,737
  • 57
  • 305
  • 359
  • Garbage-collection is expensive, so the interpreter is often "lazy" about actually doing it. Abandoned data might sit around in memory for quite some time before the garbage-collector finally runs. When it runs, it "touches" lots of data and might therefore cause many page-faults which must be handled by the OS's virtual memory manager. (Different implementations have taken different approaches to mitigate this side-effect.) – Mike Robinson Jan 16 '18 at 14:37
0

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.

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).

David Spector
  • 1,520
  • 15
  • 21
0

Another important consideration is circular references 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.

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

Is it possible to create a "weak reference" in 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 stolen in an out-of-memory situation.

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 Null before you abandon it to the garbage collector ... "Be tidy."


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.

Mike Robinson
  • 8,490
  • 5
  • 28
  • 41