簡単な答え:はい。どこにも参照されていないオブジェクトは、そのオブジェクトのプロパティによって参照されているものに関係なく、メモリから完全に削除されます。
スニペットでは、物事はかなり単純ですが、クロージャを使い始めるとmem-managementがトリッキーになる可能性があります。
var objA = (function()
{
var objAb = {who:'An object literal in closure scope',globalReference:'None!'};
return {who:'Return value, is an object literal that references a closure object'.
closureObj : objAb};
})();
var objB = {who:'some object',objAb:{who:'object literal, referenced by objB.objAb'}};
var objBAb = objB.objAb;//reference to obj literal, referenced by objB.objAb
var objAb = objA.closureObj;//reference to obj literal, referenced by objA.closureObj, which in turn references the closure object literal
delete objB.objAb;
console.log(objBAb);//<-- the object literal that was declared as a property of objB still exists
delete objAb;//<-- this reference is gone, but the closure obj still exists
console.log(objA.closureObj);//<-- object is there
基本的に、オブジェクトは名前のないエンティティです。それらにアクセスするために使用される変数は参照であり、実際のオブジェクト自体が含まれることは決してありません。それはJS空間に浮かんでいます。を使用する場合はdelete someVar
、その変数の実際の値(メモリアドレス(一種))の設定を解除するだけです。
JS GCは、オブジェクトを含むメモリ内の場所を参照する変数を見つけることができない場合、そのメモリを再利用します。
それはそれと同じくらい簡単です。
このロジックを次のコードに適用すると、次のようになります。
var objA = (function()
{
var closureObj = {iam:'An object literal defined inside a closure scope'};
var functionsAreObjects = function()
{//nameless function object, inside closure scope, too
return closureObj;
};
var resetFunction = function()
{
this.closureReference = functionsAreObjects();//assign return value to this
};
return {iam:'The returned object literal',
closureReference:closureObj,
reset:resetFunction,
getClosureReference:functionsAreObjects};
})();
delete objA.closureReference;//the closure object IS NOT GC'ed
前の例では、最後のdeleteステートメントはクロージャーオブジェクトリテラルをGCするのに十分ではありませんでした。ただし、現在objA
は2つのメソッド(関数オブジェクトを参照するプロパティ)があります。これらのメソッドは引き続きクロージャオブジェクトを参照し、によって参照されるobjA
ため、まだGCするclosureObj
ことはできません。だから、これは物事がトリッキーになるところです:
delete objA.closureReference;
delete objA.reset;
delete objA.getClosureReference;
にリンクできるすべてのプロパティを削除したclosureObj
ので、GCされるのは当然ですよね?-ええと、そうではありません。ChromeのV8はメモリの割り当てを解除しますが、Operaでリークを引き起こす同様のコードについて聞いたことがあります。おそらく、IEがメモリの再利用に優れていない可能性はあります。
また、を使用してゲッターメソッドを効果的に作成したgetClosureReference
ため、実際には、これが発生する可能性が非常に高くなります。
//do stuff
delete objA.closureReference;
var objB = objA.getClosureReference();//<-- created new reference to closure object
//do some more stuff
delete objA.reset;
delete objA.getClosureReference;
この場合、まだどこかclosureObj
で参照されているため、GCすることはできません。objB
その変数がスコープ外になった場合にのみ、closureObj
割り当てが解除されます。これはグローバル変数に対する非常に堅実な議論であるだけでなく(スコープから外れることはなく、したがってGCされることもありません)、クロージャは、きちんとしていますが、開発者からのオーバーヘッドがさらに必要であることを示しています。変数がスコープ外になるとは、必ずしもメモリが解放されることを意味するわけではありません。クロージャによっては、オブジェクトへの参照、またはそのオブジェクトを参照する関数が公開される可能性があります。
私はこの問題について少し前に質問を投稿しましたが、それはいくつかのことを説明するかもしれません。
そして、楽しみのために、ネストされたクロージャ(クロージャ内のクロージャ、クロージャ内、相互参照の受け渡し、およびその他のオブジェクト)の例が必要な場合は、次のコードで何をGCできるかを調べてみてください。