`free` operator

# Isaac Schlueter (12 years ago)

It'd be really nice if JS had a way to explicitly delete an object.

Occasionally, in complex programs, you can find yourself with a situation where a certain type of object is leaking. However, even if you track down what the object is, and find the exact point in your program where you ought to have no references to it, it's not always obvious to know what might be holding a reference still. It's tempting to do this, and newcomers often think that this helps, but of course, it does nothing:

function doStuff() { // some object that we're doing stuff with... someObject.someMethod()

// now we know we're done, and there should be no refs. // but, there are, and they're leaking. // I know! I'll do this: delete someObject // surprise! that does nothing. }

What do you folks think about a "free" operator (or something like it) that would actually do what delete looks like it does?

var obj = {} var foo = { ref: obj } var obj2 = obj free obj // obviously this syntax probably won't work, since 'free' is not a reserved word already assert(obj === undefined) assert(foo.ref === undefined) assert(obj2 === undefined)

So, any references to the freed object would be set to undefined, and presumably at some point, the GC will harvest it.

Yes, yes, I know, the proper way to fix a memory leak in JS is to properly manage references, but sometimes that means rewriting this complicated app, and it's leaking memory now, in production.

Has this been discussed before?

# Andrea Giammarchi (12 years ago)

how about

someObject = null;

rather than delete someObject;

?

free'ing' an object is like dealing with GC ... I think you would rather stay away from it and track references, and free them, as much as you can :)

# John J Barton (12 years ago)

On Thu, Oct 25, 2012 at 4:16 PM, Isaac Schlueter <i at izs.me> wrote:

It'd be really nice if JS had a way to explicitly delete an object.

I guess you mean ... a way to set all the refs to a object to undefined.

What do you folks think about a "free" operator (or something like it) that would actually do what delete looks like it does?

var obj = {} var foo = { ref: obj }

I assume that in your real life, you don't know 'foo' but somehow you know that foo.ref is never used?

Debuggers should be able to tell you all the places obj is used; I guess it's not very hard.

var obj2 = obj free obj // obviously this syntax probably won't work, since 'free'

Since you know "obj" can you set it to be a getter that returns undefined?

is not a reserved word already assert(obj === undefined) assert(foo.ref === undefined) assert(obj2 === undefined)

So, any references to the freed object would be set to undefined, and presumably at some point, the GC will harvest it.

Yes, yes, I know, the proper way to fix a memory leak in JS is to properly manage references, but sometimes that means rewriting this complicated app, and it's leaking memory now, in production.

Deleting all of the properties of obj would solve the problem as well I assume.

jjb

# Shawn Steele (12 years ago)

I sort of have a fundamental problem with the solution. Eg: If it were actually unused, it'd be GC'd. Since it isn't GC'd, something must be holding a reference to it. So if you force it to be gone, or clear all the properties, or whatever, seems to me that then you'd just start throwing random errors in the code that tried to use the "freed" object? That might be even harder to track down.

# Isaac Schlueter (12 years ago)

On Fri, Oct 26, 2012 at 1:35 AM, Shawn Steele <Shawn.Steele at microsoft.com> wrote:

I sort of have a fundamental problem with the solution. Eg: If it were actually unused, it'd be GC'd. Since it isn't GC'd, something must be holding a reference to it. So if you force it to be gone, or clear all the properties, or whatever, seems to me that then you'd just start throwing random errors in the code that tried to use the "freed" object? That might be even harder to track down.

On the contrary, "TypeError: Cannot read property 'prop' of undefined", with a stack trace, is WAY easier to track down than "The RSS on my server gradually rises, until the operating system kills it, which happens about every 4 hours."

Fast failure is not as good as success, but it's better than anything else.

On Thu, Oct 25, 2012 at 4:16 PM, Isaac Schlueter <i at izs.me> wrote:

It'd be really nice if JS had a way to explicitly delete an object.

I guess you mean ... a way to set all the refs to a object to undefined.

Yes, exactly.

On Fri, Oct 26, 2012 at 1:20 AM, John J Barton <johnjbarton at johnjbarton.com> wrote:

var obj = {} var foo = { ref: obj }

I assume that in your real life, you don't know 'foo' but somehow you know that foo.ref is never used?

Well, you know that IF foo.ref is used, it's an error, and ought to throw. Also, it's quite easy to check if the property exists, and set it to a new object if so. It's common to have things like:

if (!this._parser) { this._parser = new ParserThingie(); }

In this example, imagine that parsers are expensive to create. So, we try to reuse them (danger!), and over time, our program grows until we have some code paths where the parsers are not getting all of their data removed properly. If the parser has a ref to an object that has a reference to some other thing, etc., then you've got a memory leak.

This exact situation happened in Node's HTTP library a few months ago, and was very tedious to fix. We quite easily identified one of the things in the chain, and that it must have been linked in some way to an HTTP parser (or else it would have been GC'ed).

It would have been much easier to just find the point where we know that the HTTP response object should be "finished", and forcibly remove any references to it.

Since you know "obj" can you set it to be a getter that returns undefined?

Yeah, but the purpose of this is to take away the ref that you already have. What good is a getter that returns undefined, once you've already gotten it? Closing the barn door after the horse has left.

Deleting all of the properties of obj would solve the problem as well I assume.

But that is a bit more whack-a-mole, and expensive. Ultimately, what we did was move all of the addon properties on parsers to a single object, and delete that object when we re-use the http parser.

# Alex Russell (12 years ago)

This use-case is usually what weak refs get pressed into service for. But I think that answering your question, "why is my RSS continually increasing?" is something for a tool (debugger, profiler, etc.) to help answer. Some sort of assertion version of free() seems like the right thing: it can communicate your intent there be no refs at that point to a tool. E.g.

console.assertFree(obj);

# Rick Waldron (12 years ago)

On Thu, Oct 25, 2012 at 7:16 PM, Isaac Schlueter <i at izs.me> wrote:

It'd be really nice if JS had a way to explicitly delete an object.

Occasionally, in complex programs, you can find yourself with a situation where a certain type of object is leaking. However, even if you track down what the object is, and find the exact point in your program where you ought to have no references to it, it's not always obvious to know what might be holding a reference still. It's tempting to do this, and newcomers often think that this helps, but of course, it does nothing:

function doStuff() { // some object that we're doing stuff with... someObject.someMethod()

// now we know we're done, and there should be no refs. // but, there are, and they're leaking. // I know! I'll do this: delete someObject // surprise! that does nothing. }

What do you folks think about a "free" operator (or something like it) that would actually do what delete looks like it does?

var obj = {} var foo = { ref: obj } var obj2 = obj free obj // obviously this syntax probably won't work, since 'free' is not a reserved word already assert(obj === undefined) assert(foo.ref === undefined) assert(obj2 === undefined)

So, any references to the freed object would be set to undefined, and presumably at some point, the GC will harvest it.

Yes, yes, I know, the proper way to fix a memory leak in JS is to properly manage references, but sometimes that means rewriting this complicated app, and it's leaking memory now, in production.

This is absolutely a reality in web application development as well, specifically long running pages that might not get the benefit of a page load (think pinned tabs).

I also agree that a silver bullet would be lovely, but creating a keyword operator will break 1JS (unless previously reserved) :\

# Domenic Denicola (12 years ago)

I do think that including this as a debugging tool is where the most value is. Whether through an engine-provided API (like V8's gc()/--expose-gc) or through something more standardized, like the existing debugger statement, is the real question.

On Oct 25, 2012, at 21:04, "Alex Russell" <slightlyoff at google.com<mailto:slightlyoff at google.com>> wrote:

This use-case is usually what weak refs get pressed into service for. But I think that answering your question, "why is my RSS continually increasing?" is something for a tool (debugger, profiler, etc.) to help answer. Some sort of assertion version of free() seems like the right thing: it can communicate your intent there be no refs at that point to a tool. E.g.

console.assertFree(obj);

On Oct 25, 2012 7:58 PM, "Isaac Schlueter" <i at izs.me<mailto:i at izs.me>> wrote:

On Fri, Oct 26, 2012 at 1:35 AM, Shawn Steele <Shawn.Steele at microsoft.com<mailto:Shawn.Steele at microsoft.com>> wrote:

I sort of have a fundamental problem with the solution. Eg: If it were actually unused, it'd be GC'd. Since it isn't GC'd, something must be holding a reference to it. So if you force it to be gone, or clear all the properties, or whatever, seems to me that then you'd just start throwing random errors in the code that tried to use the "freed" object? That might be even harder to track down.

On the contrary, "TypeError: Cannot read property 'prop' of undefined", with a stack trace, is WAY easier to track down than "The RSS on my server gradually rises, until the operating system kills it, which happens about every 4 hours."

Fast failure is not as good as success, but it's better than anything else.

On Thu, Oct 25, 2012 at 4:16 PM, Isaac Schlueter <i at izs.me<mailto:i at izs.me>> wrote:

It'd be really nice if JS had a way to explicitly delete an object.

I guess you mean ... a way to set all the refs to a object to undefined.

Yes, exactly.

On Fri, Oct 26, 2012 at 1:20 AM, John J Barton <johnjbarton at johnjbarton.com<mailto:johnjbarton at johnjbarton.com>> wrote:

var obj = {} var foo = { ref: obj }

I assume that in your real life, you don't know 'foo' but somehow you know that foo.ref is never used?

Well, you know that IF foo.ref is used, it's an error, and ought to throw. Also, it's quite easy to check if the property exists, and set it to a new object if so. It's common to have things like:

if (!this._parser) { this._parser = new ParserThingie(); }

In this example, imagine that parsers are expensive to create. So, we try to reuse them (danger!), and over time, our program grows until we have some code paths where the parsers are not getting all of their data removed properly. If the parser has a ref to an object that has a reference to some other thing, etc., then you've got a memory leak.

This exact situation happened in Node's HTTP library a few months ago, and was very tedious to fix. We quite easily identified one of the things in the chain, and that it must have been linked in some way to an HTTP parser (or else it would have been GC'ed).

It would have been much easier to just find the point where we know that the HTTP response object should be "finished", and forcibly remove any references to it.

Since you know "obj" can you set it to be a getter that returns undefined?

Yeah, but the purpose of this is to take away the ref that you already have. What good is a getter that returns undefined, once you've already gotten it? Closing the barn door after the horse has left.

Deleting all of the properties of obj would solve the problem as well I assume.

But that is a bit more whack-a-mole, and expensive. Ultimately, what we did was move all of the addon properties on parsers to a single object, and delete that object when we re-use the http parser.

# Rick Waldron (12 years ago)

On Thu, Oct 25, 2012 at 9:04 PM, Alex Russell <slightlyoff at google.com>wrote:

This use-case is usually what weak refs get pressed into service for. But I think that answering your question, "why is my RSS continually increasing?" is something for a tool (debugger, profiler, etc.) to help answer. Some sort of assertion version of free() seems like the right thing: it can communicate your intent there be no refs at that point to a tool. E.g.

console.assertFree(obj);

Glad you brought this up.

While there are two weak ref strawman proposals, I've also asked Nate Rajlich to write up a rationale and approach document re: his experience with node-weak[0] to add to known resources.

Rick

[0] TooTallNate/node

# Andrea Giammarchi (12 years ago)

if you are holding it already plus you don't know what happens after that assertFree(obj) call I am not sure about the value of this assertion.

# Shawn Steele (12 years ago)

On the contrary, "TypeError: Cannot read property 'prop' of undefined", with a stack trace, is WAY easier to track down than "The RSS on my server gradually rises, until the operating system kills it, which happens about every 4 hours."

I'm not so sure. Now you know where you're using it that you didn't think you were, but you've now got something freeing it that's not supposed to. So you might have to check each of those "free"s to see where they weren't supposed to free, possibly without much context at the other end. You've traded one problem for a different one.

Sure, in simple cases you might be more easily able to fix both ends, but I'm not sure that it's wise to build a debugging workaround into the standard, even maybe making it's way into best practice. You're trying to fix the garbage collection by working around where the real bug is. At some point you defeat the purpose of the garbage collection.

Seems to me like something for a debugger. I could also see a developer trying the "delete-every-property" thing as a temporary debugging technique.

# Andrew Paprocki (12 years ago)

On Thu, Oct 25, 2012 at 10:14 PM, Shawn Steele <Shawn.Steele at microsoft.com> wrote:

On the contrary, "TypeError: Cannot read property 'prop' of undefined", with a stack trace, is WAY easier to track down than "The RSS on my server gradually rises, until the operating system kills it, which happens about every 4 hours."

I'm not so sure. Now you know where you're using it that you didn't think you were, but you've now got something freeing it that's not supposed to. So you might have to check each of those "free"s to see where they weren't supposed to free, possibly without much context at the other end. You've traded one problem for a different one.

I can offer that we do this pretty commonly with certain native objects wrapped into JS and that it is useful, albeit trading problems, as you say. My personal observation is that it is much easier for a large body of JS programmers to grasp this "use-after-free" class of bugs than tracking down GC related issues such as a closure capturing a scope to which someone unknowingly added a variable keeping a whole tree of things alive.

I would love it if tools could to a better job at illustrating why objects are kept alive, though. There is no desire to standardize JS bytecode or anything of that nature, but perhaps there is room to standardize some kind of serialized GC heap view akin to a 'core' file for debugging purposes so that tool writers have an easier job?

# Domenic Denicola (12 years ago)

On Oct 25, 2012, at 23:13, "Andrew Paprocki" <andrew at ishiboo.com> wrote:

On Thu, Oct 25, 2012 at 10:14 PM, Shawn Steele <Shawn.Steele at microsoft.com> wrote:

On the contrary, "TypeError: Cannot read property 'prop' of undefined", with a stack trace, is WAY easier to track down than "The RSS on my server gradually rises, until the operating system kills it, which happens about every 4 hours."

I'm not so sure. Now you know where you're using it that you didn't think you were, but you've now got something freeing it that's not supposed to. So you might have to check each of those "free"s to see where they weren't supposed to free, possibly without much context at the other end. You've traded one problem for a different one.

I can offer that we do this pretty commonly with certain native objects wrapped into JS and that it is useful, albeit trading problems, as you say. My personal observation is that it is much easier for a large body of JS programmers to grasp this "use-after-free" class of bugs than tracking down GC related issues such as a closure capturing a scope to which someone unknowingly added a variable keeping a whole tree of things alive.

I would love it if tools could to a better job at illustrating why objects are kept alive, though. There is no desire to standardize JS bytecode or anything of that nature, but perhaps there is room to standardize some kind of serialized GC heap view akin to a 'core' file for debugging purposes so that tool writers have an easier job?

There are already some pretty good debugging tools for inspecting the JS heap, both in Web Inspector and (for IE/Windows 8 users) in Visual Studio 2012 Update 1. Standardizing them seems not that useful; they're already working well.

The new thing this proposal brings to the table is the ability to mark, from within your code, exactly what object you're worried about the leakiness of. You also get very understandable error messages for determining who's using that object. Pouring through the list of retained objects, trying to find the one you're concerned about by looking through ambiguous short names or via the profiler's deep tree hierarchy, is not nearly as straightforward.

# John J Barton (12 years ago)

On Oct 25, 2012 8:42 PM, "Domenic Denicola" <domenic at domenicdenicola.com>

wrote:

The new thing this proposal brings to the table is the ability to mark,

from within your code, exactly what object you're worried about the leakiness of. You also get very understandable error messages for determining who's using that object. Pouring through the list of retained objects, trying to find the one you're concerned about by looking through ambiguous short names or via the profiler's deep tree hierarchy, is not nearly as straightforward.

But don't you get that by just changing one line to var obj = undefined; ? jjb

# Yehuda Katz (12 years ago)

Any proposal that destroys this invariant:

function() { var x = obj();

// other statements not involving x

x // still defined }

destroys local reasoning and would almost certainly do more harm than good.

In programs with leaks, the leak is often inside of library code, and breaking the library's own invariants will cause more confusion, not less, in many cases.

I shudder to think about bug reports I would receive in my libraries where someone forced a variable reference I was holding to become undefined or start throwing if I try to reference it.

-- Yehuda Katz (ph) 718.877.1325

# David Herman (12 years ago)

On Oct 25, 2012, at 9:38 PM, Yehuda Katz <wycats at gmail.com> wrote:

Any proposal that destroys this invariant:

function() { var x = obj();

// other statements not involving x

x // still defined }

destroys local reasoning and would almost certainly do more harm than good.

Agreed. This is analogous to the idea of Proxy.attach, where any (non-local) code can come along and mutate meta-level behavior of an object. In the case of Proxy.attach, it's modifying the behavior of the various object operations. In the case of `free' it's modifying the object-ness entirely.

# Patrick Mueller (12 years ago)

On Thu, Oct 25, 2012 at 8:20 PM, John J Barton <johnjbarton at johnjbarton.com>wrote:

On Thu, Oct 25, 2012 at 4:16 PM, Isaac Schlueter <i at izs.me> wrote:

It'd be really nice if JS had a way to explicitly delete an object.

I guess you mean ... a way to set all the refs to a object to undefined.

Isaac's free sounds like Smalltalk's one-way become: nil:

live.exept.de/doc/online/english/programming/classicBugs.html#BUG8, gbracha.blogspot.com/2009/07/miracle-of-become.html

Probably not the best idea to be using this in production code. For debugging though, AWESOME. And once we have classes, allInstances() will be nice as well. :-)

Wondering if, for node.js anyway, you could use the V8 HeapSnapshot to find your references:

http://v8.googlecode.com/svn/trunk/include/v8-profiler.h

Didn't proxies have some way of doing a become: and freezing themselves as a new object? Maybe that was the older Proxy stuff, didn't see it in the current drafts. But did see "Revokable Proxies", which sounds like it might fit the bill, though you'd have to arrange to proxy the sketchy object early:

http://wiki.ecmascript.org/doku.php?id=strawman:revokable_proxies
# David Herman (12 years ago)

A feature you shouldn't use in production is a feature your attackers will use in production. ;)

# David Bruant (12 years ago)

Le 26/10/2012 07:28, Patrick Mueller a écrit :

On Thu, Oct 25, 2012 at 4:16 PM, Isaac Schlueter <i at izs.me
<mailto:i at izs.me>> wrote:
It'd be really nice if JS had a way to explicitly delete an object.

Didn't proxies have some way of doing a become: and freezing
themselves as a new object?  Maybe that was the older Proxy stuff,
didn't see it in the current drafts.  But did see "Revokable
Proxies", which sounds like it might fit the bill, though you'd
have to arrange to proxy the sketchy object early:

    http://wiki.ecmascript.org/doku.php?id=strawman:revokable_proxies

Indeed. Basically, the revoke functions is a 'free' operator specialized for the generated proxy. Proxies still leaks (that's unavoidable), but the underlying target does not. My original post on the topic (where I mention a use case equivalent to Isaacs') esdiscuss/2012-August/024344

I'm strongy against a free operator, because if it's in a language, it'll be in a node module (or any update...) and people may use it to randomly free objects I created. The module may have been corrupted (by a bug) and the inclusion of a naive free operator would be impossible to defend against.

I see an analogy with Dave's post on coroutines [1] (which I think is mistitled because what is said stands beyond the web context). The ability to stop the stack provides authority to library authors that can't be defended against when you import the library and make it harder for you to reason about your program. Generators are a sweet spot between what we expect from coroutines and not providing abusive authority. I think revokable proxies are also a sweet spot between being able to free memory (or rather make memory freeable) and not providing the abusive authority to arbitrarily free anything at anytime.

Regarding "it's a problem I have in node.js in production right now!!!", proxies (including the revokable part) have been agreed on by TC39 and are "a V8 issue away" [2] with already a partial implementation (though from the previous design). On the other hand, the "free" operator is meeting resistance on es-discuss (and I assume it won't be agreed on by TC39 as proposed).

David

[1] calculist.org/blog/2011/12/14/why-coroutines-wont-work-on-the-web [2] code.google.com/p/v8/issues/detail?id=1543

# Patrick Mueller (12 years ago)

On Fri, Oct 26, 2012 at 2:03 AM, David Herman <dherman at mozilla.com> wrote:

A feature you shouldn't use in production is a feature your attackers will use in production. ;)

Not just your attackers. Worse. You, probably. I often thought, while I was a Smalltalker, "hey, I can use become: here" or "I'll just add a finalization block for this object here". Always the wrong thing to do. Eventually I learned to avoid even considering using the magic sauces. But it's hard to resist.

Perhaps we need to start talking about lower-level user space capabilities like this, that we can provide for "debugging". Presumably, a user gesture would be required to "enter debug mode", but once you're there, you have access to some of the magic. In browser debuggers, the "console" REPL would give you access to this, and from node the REPL could do this. Instead of "use strict", it would be a kind of "use magic".

# David Bruant (12 years ago)

Le 26/10/2012 13:59, Patrick Mueller a écrit :

On Fri, Oct 26, 2012 at 2:03 AM, David Herman <dherman at mozilla.com <mailto:dherman at mozilla.com>> wrote:

A feature you shouldn't use in production is a feature your
attackers will use in production. ;)

Not just your attackers. Worse. You, probably. "you" belongs to the "your attackers" group for all humans writing code I've met so far I think ;-)

Perhaps we need to start talking about lower-level user space capabilities like this, that we can provide for "debugging". Presumably, a user gesture would be required to "enter debug mode", but once you're there, you have access to some of the magic.

If "user space" implies "will be accessible to a webpage", it's not workable. I think debugging capabilities should stay in debugging-land (which userland cannot interact with).

# John J Barton (12 years ago)

On Thu, Oct 25, 2012 at 5:58 PM, Isaac Schlueter <i at izs.me> wrote:

<johnjbarton at johnjbarton.com> wrote:

var obj = {} var foo = { ref: obj }

I assume that in your real life, you don't know 'foo' but somehow you know that foo.ref is never used?

Well, you know that IF foo.ref is used, it's an error, and ought to throw. Also, it's quite easy to check if the property exists, and set it to a new object if so. It's common to have things like:

if (!this._parser) { this._parser = new ParserThingie(); }

In this example, imagine that parsers are expensive to create. So, we try to reuse them (danger!), and over time, our program grows until we have some code paths where the parsers are not getting all of their data removed properly. If the parser has a ref to an object that has a reference to some other thing, etc., then you've got a memory leak.

This exact situation happened in Node's HTTP library a few months ago, and was very tedious to fix. We quite easily identified one of the things in the chain, and that it must have been linked in some way to an HTTP parser (or else it would have been GC'ed).

It would have been much easier to just find the point where we know that the HTTP response object should be "finished", and forcibly remove any references to it.

Debugging tools lag other tools in part because test-cases or use-models are hard not readily available. Bugs by their nature are mysterious when unsolved and embarrassing when solved. Example code for this case with insight on why it was hard could generate competition to create tools to solve similar cases. Benchmarks for debugging tools are badly needed.

The problem you outlined has two very different phases. First is to isolate the leaker. This is a hard problem; recent improvements in Chrome devtools HeapProfiler can help. Second is plugging the leak, the problem you posted about. The analysis of a program by combined source and runtime analysis is the kind of problems I'm working on. Specific cases would be really helpful.

The js-tools group would be ideal for more discussions of these issues: groups.google.com/forum/?fromgroups=#!forum/js-tools

jjb

# Patrick Mueller (12 years ago)

On Fri, Oct 26, 2012 at 11:51 AM, John J Barton <johnjbarton at johnjbarton.com

wrote:

Debugging tools lag other tools in part because test-cases or use-models are hard not readily available.

But the only debugging tools we really have are proprietary low-level APIs (eg, V8 debug stuff), and some existing debug ui frameworks (eg, Web Inspector). The barrier is so, so high for this stuff. Compared to a number of other environments where the barrier is not so high. Eg, in C, if you're debugging memory issues, switching to using a debug malloc library isn't a huge barrier.

It would be nice to lower the barrier, expose some "debug" stuff in JS. Implying that I want "debug APIs" available in JS, and I want to write my debug helpers in JS.

V8's --expose-debug-as (or whatever) trick is a step in the right direction. It would be nice to have some commonality here, so I don't have to write one set of debug helpers for V8, another for JSC, another for *Monkey, etc.

The js-tools group would be ideal for more discussions of these issues: groups.google.com/forum/?fromgroups=#!forum/js-tools

Ah, nice. I'll stop pestering here, and start pestering there. :-)

# Isaac Schlueter (12 years ago)

So, yes, you can certainly use debugging tools to find which objects are leaking. But, there are times when you have a program where something is leaking, and you read through the code, and see that there is no possible way that it could be leaking (but it is, as reality sometimes stubbornly refuses to be told what to do.)

Use-after-free bugs are not great, but they are relatively easy to track down. And, in general, a program that crashes when it does something wrong, is handling it exactly right. Slowly leaking memory is much harder to diagnose, and usually much harder to correct.

We've got some band-aids in place in the node http.js file to prevent parser leaks. A more forcible free() method would have made it much easier. The long-term solution is to rewrite the program so that it's not so badly architected, but as is so often the case, we didn't realize the architectural mistakes until we had made them, and fixing them is quite costly. (Node's http implementation will get a massive refactor in 0.12.)

Yehuda's "action at a distance" complaint is definitely a valid concern. However, note that an object can't be freed unless you have a reference to the object. Thus, any code that would set my reference to undefined could only do so if it was also capable of mutating the object in any other way (adding/removing properties, etc.)

So, we already have this:

function () { // acquire a ref from some external code // no way of knowing what else is sharing this object var x = func() x.foo = 'bar' // other code... doAnotherThing() // not guaranteed! assert(x.foo === 'bar') }

Whenever you have a reference to an object that is shared with some other code, there's the potential for action at a distance. The proposal here is to make that action a bit more powerful.

I don't agree that it's necessarily a problem in production. We free objects in other languages all the time.

# Rick Waldron (12 years ago)

On Fri, Oct 26, 2012 at 2:58 PM, Isaac Schlueter <i at izs.me> wrote:

So, yes, you can certainly use debugging tools to find which objects are leaking. But, there are times when you have a program where something is leaking, and you read through the code, and see that there is no possible way that it could be leaking (but it is, as reality sometimes stubbornly refuses to be told what to do.)

Use-after-free bugs are not great, but they are relatively easy to track down. And, in general, a program that crashes when it does something wrong, is handling it exactly right. Slowly leaking memory is much harder to diagnose, and usually much harder to correct.

We've got some band-aids in place in the node http.js file to prevent parser leaks. A more forcible free() method would have made it much easier. The long-term solution is to rewrite the program so that it's not so badly architected, but as is so often the case, we didn't realize the architectural mistakes until we had made them, and fixing them is quite costly. (Node's http implementation will get a massive refactor in 0.12.)

Yehuda's "action at a distance" complaint is definitely a valid concern. However, note that an object can't be freed unless you have a reference to the object. Thus, any code that would set my reference to undefined could only do so if it was also capable of mutating the object in any other way (adding/removing properties, etc.)

So, we already have this:

function () { // acquire a ref from some external code // no way of knowing what else is sharing this object var x = func() x.foo = 'bar' // other code... doAnotherThing() // not guaranteed! assert(x.foo === 'bar') }

Whenever you have a reference to an object that is shared with some other code, there's the potential for action at a distance. The proposal here is to make that action a bit more powerful.

I don't agree that it's necessarily a problem in production. We free objects in other languages all the time.

Isaac, Would you be interested in or willing to create an experimental prototype (ie. behind a flag) in node? I think you're in a particularly strong position to make a case for the proposal :)

# John J Barton (12 years ago)

On Fri, Oct 26, 2012 at 11:58 AM, Isaac Schlueter <i at izs.me> wrote:

So, yes, you can certainly use debugging tools to find which objects are leaking. But, there are times when you have a program where something is leaking, and you read through the code, and see that there is no possible way that it could be leaking (but it is, as reality sometimes stubbornly refuses to be told what to do.)

Use-after-free bugs are not great, but they are relatively easy to track down. And, in general, a program that crashes when it does something wrong, is handling it exactly right. Slowly leaking memory is much harder to diagnose, and usually much harder to correct. ...

Yehuda's "action at a distance" complaint is definitely a valid concern. However, note that an object can't be freed unless you have a reference to the object. Thus, any code that would set my reference to undefined could only do so if it was also capable of mutating the object in any other way (adding/removing properties, etc.)

So, we already have this:

function () { // acquire a ref from some external code // no way of knowing what else is sharing this object var x = func() x.foo = 'bar' // other code... doAnotherThing() // not guaranteed! assert(x.foo === 'bar')

FWIW, Querypoint debugging will be able to tell you "where was x.foo changed?".

}

Whenever you have a reference to an object that is shared with some other code, there's the potential for action at a distance.

Seems like other questions we'd like to answer include "where was the object refed by 'x' defined?" "Where are other references to that object taken?" "Where was any property of 'x' written?" These seem feasible.

jjb

# Yehuda Katz (12 years ago)

An optimal debugger would show the textual location in the source code where live references to a particular object were created. Optimally, it would be possible to get the references during debug mode via the "tooltip" that comes up when hovering over a variable.

Isaac could then solve his problem trivially by adding a debugger where he would have called free and look at what other places in the source are still holding references.

# Russell Leggett (12 years ago)

Yehuda's "action at a distance" complaint is definitely a valid concern. However, note that an object can't be freed unless you have a reference to the object. Thus, any code that would set my reference to undefined could only do so if it was also capable of mutating the object in any other way (adding/removing properties, etc.)

So, we already have this:

function () { // acquire a ref from some external code // no way of knowing what else is sharing this object var x = func() x.foo = 'bar' // other code... doAnotherThing() // not guaranteed! assert(x.foo === 'bar') }

Whenever you have a reference to an object that is shared with some other code, there's the potential for action at a distance. The proposal here is to make that action a bit more powerful.

JavaScript is mutable enough. I wouldn't want this anywhere near my code or any library I ever used. It completely removes control from someone writing code. Yes, mutation is possible now, but numbers, boolean, and strings are not, and you can freeze and object if you want to. You said yourself that the problem is with the code that is doing the leaking. Better tools to fix your code is a nice addition, but adding an operator like this has the potential to add weird bugs all over. If you're only working on your own code base, maybe a tool like this is fine, shoot yourself in the foot, but in an eco-system of sharing packages and libraries, etc. this is just more ammunition to bad practice. If you are skilled enough to know the right time to use an operator like this, you're skilled enough to fix your code. If its hard to fix, tools could surely assist.

# John J Barton (12 years ago)

On Fri, Oct 26, 2012 at 1:19 PM, Yehuda Katz <wycats at gmail.com> wrote:

An optimal debugger would show the textual location in the source code where live references to a particular object were created.

A concrete example would ensure that we imagine the same things, but for var foo = { ref: obj } var obj2 = obj we see that recording initializers and assignments using the identifier 'obj' will give the raw material for this tool. These traces must then be filtered to the ones where 'obj' references the particular object Isaac is tracing. That is the same procedure as Querypoint's lastChange, but with different AST nodes being traced.

Optimally, it would be possible to get the references during debug mode via the "tooltip" that comes up when hovering over a variable.

Yes, though my current implementation drives a side panel with mouseover-ish rather than tooltips to allow a more complete UI.

Isaac could then solve his problem trivially by adding a debugger where he would have called free and look at what other places in the source are still holding references.

I hope for "trivially" but I'll settle for "with relative ease".

jjb

# Jorge (12 years ago)

On 26/10/2012, at 01:16, Isaac Schlueter wrote:

It'd be really nice if JS had a way to explicitly delete an object.

Occasionally, in complex programs, you can find yourself with a situation where a certain type of object is leaking. However, even if you track down what the object is, and find the exact point in your program where you ought to have no references to it, it's not always obvious to know what might be holding a reference still. It's tempting to do this, and newcomers often think that this helps, but of course, it does nothing:

function doStuff() { // some object that we're doing stuff with... someObject.someMethod()

// now we know we're done, and there should be no refs. // but, there are, and they're leaking. // I know! I'll do this: delete someObject // surprise! that does nothing. }

What do you folks think about a "free" operator (or something like it) that would actually do what delete looks like it does?

var obj = {} var foo = { ref: obj } var obj2 = obj free obj // obviously this syntax probably won't work, since 'free' is not a reserved word already assert(obj === undefined) assert(foo.ref === undefined) assert(obj2 === undefined)

So, any references to the freed object would be set to undefined, and presumably at some point, the GC will harvest it.

Yes, yes, I know, the proper way to fix a memory leak in JS is to properly manage references, but sometimes that means rewriting this complicated app, and it's leaking memory now, in production.

Has this been discussed before?

Hi Isaac,

I have some random thoughts about this:

1.- In a program that creates zillions of short lived objects gc()s often take too long, and -I guess- the ability to explicitly free(noLongerWantedObject) could be of great help here, for the GC machinery. So much that the API could perhaps be gc(object) instead of free(object), and destroy it on the fly instead of having to wait for the GC to kick in.

2.- If a frozen objectA holds a reference to objectB, should a call to free(objectB) mutate frozen objectA? Does not sound good...

3.- I have the gut feeling that a free(noLongerWantedObject) could under certain circumstances become insanely expensive, perhaps as long as a gc() call, looking for might-be-references to noLongerWantedObject everywhere.

4.- If you could mutate the object (keeping its identity) to a frozen {} empty object, perhaps you'd get the same functionality you're after in a way that (again, my gut feeling) would be easier to implement, (often) faster to run, and even shimmable:

function empty (object) { Object.getOwnPropertyNames(object).forEach({|p| delete p}); object.proto= {}.proto; Object.freeze(object); }

On the other hand, I have to say that I sympathize very much with the idea of being able to say "destroy and garbage collect this object right now, no matter what, no matter who else might hold a reference to it". But that's because I don't buy so much the argument "with feature x people are going to shoot themselves in their feet" as "with power comes responsiblity".

# Herby Vojčík (12 years ago)

Issac, what about the already mentioned way of revokable proxies? Why don't you go that way - it should be pretty easy to create (primitive version of) them at C++ level, if they're not in V8 yet. Just a wrapper around the object forwarding everything to its target until it gets the signal to stop that, whereupon it frees the reference (thus, GC clears it). You can even log / throw at the point of access-past-revocation, thus find the code that holds and uses it.

# David Bruant (12 years ago)

2012/10/26 Isaac Schlueter <i at izs.me>

(...)

We've got some band-aids in place in the node http.js file to prevent

parser leaks. A more forcible free() method would have made it much easier. The long-term solution is to rewrite the program (...)

So you're suggesting that a language-level feature with abusive authority introducing use-after-free bugs (and maybe others) should be included to solve short-term problems?

Yehuda's "action at a distance" complaint is definitely a valid concern. However, note that an object can't be freed unless you have a reference to the object.

Everyone has a reference to built-ins so a bug or an attacker could free built-ins.

Thus, any code that would set my reference to undefined could only do so if it was also capable of mutating the object in any other way (adding/removing properties, etc.)

So, we already have this:

function () { // acquire a ref from some external code // no way of knowing what else is sharing this object var x = func() x.foo = 'bar' // other code... doAnotherThing() // not guaranteed! assert(x.foo === 'bar') }

With non-configurable properties and making objects non-extensible, you have a way to prevent this, a way to protect your objects from "action at a distance". Even proxies are required to respect some invariants for the sake of application securability. The free operator you're proposing cannot be protected against. Anyone can release any object it has a reference to without the object creator (or the other object reference holder) having their word to say to prevent it. That's unbalanced.

Whenever you have a reference to an object that is shared with some other code, there's the potential for action at a distance. The proposal here is to make that action a bit more powerful.

I don't agree that it's necessarily a problem in production. We free objects in other languages all the time.

I agree with you, C and C++ are absurdly unsafe languages. No wonder double free and use after-free bugs are so common! As the rumor goes, use-after-free bugs lead to security issues sometimes [1]. Really not an example to follow in my opinion.

What do you think about the revokable proxy solution? I agree it's less sexy than a 4-letter keyword operator, but it's close enough to standard and seems to solve your short-term issue as efficiently. Tom's shim [2] simulates the direct proxy API on top of the current V8's one. It includes revokable proxies I see. It can work today (as in Sat Oct 27th 2012) I think.

David

[1] www.mozilla.org/security/announce/2012/mfsa2012-85.html (just pick the first result Google gave me against "use after free security"). [2] tvcutsem/harmony

# Bill Frantz (12 years ago)

There are a few older systems which have had features that are a bit like those people are describing for the "free" operator. Let me describe two of them.

OS/360 and the PL/I language had the idea of "subpools". Many small objects could be allocated in a subpool, and all freed with one call, a high performance way of freeing storage. Neither of these systems actually NULLed existing pointers, so it was easy to make programming errors.

The KeyKOS (aka Gnosis) [1,2] depended on explicit freeing of objects for storage reclamation. As an OS, object lifetimes ranged from milliseconds to years. The reason of having an explicit free was to allow an accounting entity paying for storage to stop paying, regardless of whether others were using that storage. When the "free" call returned, all references to the storage were changed to null.

The experience in KeyKOS was that after an object had been shared for a few months, the effects of freeing it could not be predicted easily. This made it hard to decide to free an object. A combination of garbage collection and explicit free might have worked well, but was never implemented.

The naive program, using a freed object would crash. These crashes can be caught by a "keeper" object which can clean up and report failure to callers.

[1] www.cis.upenn.edu/~KeyKOS/agorics/KeyKos/Gnosis [2] cap-lore.com/CapTheory/KK/Kernel

Cheers - Bill


Bill Frantz | "I wish there was a knob on the TV to turn up the 408-356-8506 | intelligence. There's a knob called "brightness", but www.pwpconsult.com | it doesn't work.

# Brendan Eich (12 years ago)

Of course we are not going to add unsafe manual memory management to JS. No need to worry about that!

Isaac proposed safe yet horribly inefficient memory management, whereby any unwanted strong refs are found (by a global scan) and then nulled or set to undefined. This is bad for the reasons given on the thread, but also because it requires a full GC in general.

Safe and efficient manual memory management is a feature of Rust and other languages which range from "Research" to (at best) "Advanced Technology", and which seem to require fancy type/ownership systems.

As a debugging tool, something like Alex's assertFree (of course, you couldn't have a weak ref to pass in, so maybe assertSingleRef is a better name) could be done. Again, in some (many high performance) implementations, it would require a full mark/sweep GC. So it is a debug-build or debug-mode only tool, not to be used lightly.

What I did years ago as a debugging tool in SpiderMonkey, which I believe survives in the JS_DumpHeap C API, is along these lines. Rather than null any leaky paths to cover up the bug, it dumps all paths by which the allegedly single-ref (or just mysteriously still-alive) GC-thing-to-find that you pass in as an optional parameter still is connected to the graph of rooted live things.

The path names are formed by property names with unambiguous or sufficiently unlikely separators. Internal strong refs (e.g., roots in native data structures held as opaque or private parts of a JS object, e.g. a DOM object peering a C++ struct or class instance) may be given constant-string names when made strong (rooted).

Usually when debugging a leak, getting the set of strong-ref paths leads quickly to progress in fixing the bug.

# Hudson, Rick (12 years ago)

Another performance killing but valuable heap debugging tool, implementable if you have a GC write barrier that covers all pointer writes, is to have the write barrier trace any and all writes/overwrites of the pointer to the traced object. It isn't magic and the GC has to also trace the object as it is moved about but it is a step in the right direction and a tool I have used to debug GC implementations.

This type of functionality should be part of the debugger / software development environment and not part of the language, performant runtime, or ES standard.