简体   繁体   中英

JavaScript new keyword and memory management

Coming from C++ it is hard grained into my mind that everytime I call new I call delete . In JavaScript I find myself calling new occasionally in my code but (hoping) the garbage collection functionality in the browser will take care of the mess for me.

I don't like this - is there a delete method in JavaScript and is how I use it different from in C++?

Thanks.

var component = new Component();
component = null; // delete this at next garbage collection

Incidentally, the "new" keyword isn't really necessary in javascript, and has nothing (directly) to do with allocating memory. All "new" does is pass a new, empty object called "this" (this = {}) as a hidden argument to the function.

var MyClass = function(){
    // fresh empty object "this" gets passed to function
    // when you use the "new" keyword 
    this.method = function(){}
}

var myInstance = new MyClass();

Javascript can get kind of hairy with nested closures and multiple "this" variables floating around in different scopes. I prefer to do it this way:

var MyNoNewClass = function(){
    // I find this more explicit and less confusing
    var self = {}
    self.method = function(){}
    return self;
}

var myNoNewInstance = MyNoNewClass()

All JavaScript memory is referenced, but not in the traditional sense. Memory is referenced not by memory address but by a string. In this code:

var x = new someObj();

That object is referenced by the string "x" from that point forward. x is not a pointer to some memory on the heap at that point. If you assigned xa property then:

x.someProp = 42;

Then someProp is a string in memory referencing the value 42. Consequently that lets you use array notation to access it by it's string representation:

x["someProp"]++;

It's also why variables can hold any value as they don't have need of size.

Memory is collected in JavaScript, effectively, when no more strings (aka variables or property names) are referencing it. That object will be collected when x is assigned any other value. You could set it to null , undefined , or anything else and that memory will be collected.

That is, it will be collected when the browser or whatever JavaScript engine gets around to it.

Delete only removes properties from objects. From then on attempting to access that property will return undefined . For the most part, the following 2 lines of code are equivalent:

x["someProp"] = undefined;
delete x.someProp;

Edit: Ok, internally the two lines aren't the same. The delete operator will remove the "someProp" reference from memory, while setting it to undefined won't. I think. I can't find anything in the specs about setting a variable or property to undefined, but I don't think doing so does anything special.

The important thing to note is that you won't be able to delete properties that have a certain flag set, but you can set them to null or undefined (if they're not wrapped by a setter and even allow that to happen).

Taken outside of the context (the browser) the javascript is fully capable of reclaiming the memory through garbage collection. Going back to reality garbage collection in combination with DOM model can cause memory leaks.

Here is one article http://www.ibm.com/developerworks/web/library/wa-memleak/ you can find more details about it

To avoid memory leaks

  1. Ensure you remove all event handlers, so if you add like a mouse down event handler ensure you remove it when you finish
  2. if you add elements to the DOM, remove them when done
  3. if you have an object that points to another object, remove the reference when the object is done with.
  4. when you are finish with any object set it to null.

deletes just gonna remove a property from an object.

There is a delete . However, an actual need for it will be rare. It's not like C++ delete, though.

delete in JavaScript will remove a property from an object. Subsequent accesses of that property will return undefined. I assume it will be able to free any associated memory on subsequent garbage collects.

Don't use delete in JavaScript unless you are removing event handlers. Even then, we only do this because there is a memory leak associated with this practice in older versions of IE. Douglas Crockford explains this pretty well. In his case, he doesn't even use delete . He simply sets the values in question to null .

From the MDC :

The delete operator deletes a property of an object, or an element at a specified index in an array.

The delete operator in my opinion is only useful when you want to remove a property from an object. But since there might be other references to the property that it were referencing, it wont be really GCed. If you want something to be GCed, you need to remove all pointers pointing at it and also free the closures containing references to it ( more info on the topic ).

new creates objects from a constructor. delete removes properties from an object. These are two very different things.

You don't have to delete objects you created. The GC takes care of this.

delete o.fu is different from o.fu = undefined . Try this:

var o = {};
alert(o.hasOwnProperty('fu')); // -> false
o.fu = undefined;
alert(o.hasOwnProperty('fu')); // -> true
delete o.fu;
alert(o.hasOwnProperty('fu')); // -> false

There is a delete in Javascript, but trust me: it's way different than delete in something like C++. I recommend you don't even think about using it until you're more comfortable with Javascript.

Garbage collection works, though it doesn't defeat the problem of memory leaks.

The "new" keyword has nothing to do with memory. It's purpose is only to setup the prototype chain.

// C++
Foo* foo = new Foo();                      // allocate and construct

// JS "sugar" using the new keyword
var foo = new Foo();                       // allocate and construct
assert(foo instanceof Foo);

// JS constructing objects without "new"
var foo = Object.create(Foo.prototype);    // allocate with prototype
Foo.call(foo);                             // construct
assert(foo instanceof Foo);

// construct Foo with missing prototype
var foo = {};                              // allocate without prototype
Foo.call(foo);                             // construct without prototype
assert(!(foo instanceof Foo));

// so the corollary operations in JS are
foo = {};
foo = null;

// where-as this is an error (or most certainly not what you want)
delete foo;

// and this is how delete is used
foo = {bar: 42};
assert(foo.bar === 42);
delete foo.bar;
assert(foo.bar === undefined);

// but by deleting a property, you remove the reference to the object
foo = {bar: {baz: 31}};
delete foo.bar;            // remove only reference to "bar" object
// JS GC will now take over

So no, you can't delete objects. But you can delete references to objects, which may trigger object deletion by the GC. But of course, local variables (and global) can't be deleted. They simply go out of scope, de-referencing any associated objects, and potentially freeing memory, but only if the object wasn't returned or is still referenced elsewhere.

It's important to realize that because JS doesn't support pointers, GC can be perfect. At any point, the GC can simply walk the entire set of objects "seen" from any in-scope function and guarantee it doesn't miss anything like cycles, etc.

As long as you use JS in a functional style and don't try to build global god objects which tie everything together, memory management should be a non-issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM