0

I'm sure this has been asked before, but I'm not finding it.

What is the memory usage on the following sample Javascript closure:

var f = (function(sz){
    var obj = {
        x : sz,
        y : new Array(sz),
    };

    var _x = obj.x;

    return function() {
        return obj.x;
    };
})(1000000);

How much of obj is supposed to be retained for the resulting closure? Will all of obj be held in memory, or just that for obj.x?

I should say that I tried (like a newbie) to use the heap profiler in Google Chrome. Before the closure, total heap size is 5.3MB. After closure, when I set obj.y array size (sz) to 1,000,000, total heap size was 13.2MB with f retaining 8MB. This suggest that obj.y remains in memory. And when I changed sz to 10,000,000, heap size was 81.9MB, and f retaining a healthy 80MB. Consistent with obj.y remaining. But when I used sz of 100,000,000, the profile shows a heap size of only 5.6M, and f retaining 0.5MB. This tells me that obj.y was taken out with the garbage. And at all times, f() return the correct value, so presumably, the closure works as expected.

So the question remains, what is held in memory for the above closure? Obviously, I know what it CAN be, but what is it suppose to be?

codechimp
  • 1,509
  • 1
  • 14
  • 21
  • 2
    One thing to note, `new Array(n)` doesn't (necessarily) take much memory because the array is created with "empty slots" - try `new Array(sz).fill('')` to see the difference – Jaromanda X Feb 26 '17 at 22:04
  • 1
    Afaik, garbage collection for closures is [done per variable](http://stackoverflow.com/questions/5326300/garbage-collection-with-node-js), but not per object property. It would need to make a great deal of assumptions about the usage of the object. – Bergi Feb 26 '17 at 23:56

1 Answers1

2

I think you can tell if the full object is included in the closure by putting a breakpoint in the debugger on the line return obj.x;, and then adding a line to execute the function held by f to trigger it:

f();

When at that breakpoint, you can query the object obj, and you will see it is, indeed, the whole object. So I would say, yes, all of obj is held in the closure based on that.

I tested this using node and using a Chrome browser with the same results. Perhaps others javascript engines optimize this and behave differently.

Regarding garbage collection, I would say gauging things on what the garbage collector does is challenging since when this occurs is rather unpredictable and dependent on a lot of factors.

EDIT - ADDITIONAL INFORMATION

I would like to provide greater clarity on what is going on here with the closure. In JavaScript, garbage collection will only occur on things (variables, functions, ...) that are not reachable. As long as something is reachable it will not be garbage collected.

To see the closure that this function holds we can use the console.dir() command in a console.

Here's a sample console session (Chrome browser console):

> var f = (function(sz){
    var obj = {
        x : sz,
        y : new Array(sz),
    };

    var _x = obj.x;

    return function() {
        return obj.x;
    };
  })(1000000);
<- undefined
> console.dir(f)
  function anonymous()
    arguments: null
    caller: null
    length: 0
    name: ""
    prototype: Object
    __proto__: ()
    [[FunctionLocation]]: VM24461:9
    [[Scopes]]: Scopes[2]
      0: Closure
        obj: Object
          x: 1000000
          y: Array[1000000]
         __proto__: Object
      1: Global
<- undefined

Now, what is of interest here is under [[Scopes]] where we see the closure for this function, and in that closure is obj. This means that obj is reachable and so cannot be garbage collected. It also means that obj.y is reachable (through obj) and so cannot be garbage collected either.

Hopefully, that helps to provide further clarity. The console.dir() is very handy in seeing more on closures.

rasmeister
  • 1,986
  • 1
  • 13
  • 19
  • I think you are right. If tried the debugger (also like a newbie) and observed same. But when I replace with `return _x`, `obj` is no longer observable. – codechimp Feb 26 '17 at 22:53