2

私の理解では、JSガベージコレクターは、参照されなくなったオブジェクトを削除します。オブジェクトへの参照を削除し、そのオブジェクトに別のオブジェクトへの参照であるプロパティがあるとします。両方のオブジェクトが削除されますか?

例えば

var objectA = {
    prop1: "property",
    prop2: "property"
}

var objectB = {
    refToA: objectA
}

// Remove reference to objectA
delete objectA;

// Remove reference to objectB
delete objectB

両方のオブジェクトがメモリから完全に削除されましたか?

4

1 に答える 1

3

簡単な答え:はい。どこにも参照されていないオブジェクトは、そのオブジェクトのプロパティによって参照されているものに関係なく、メモリから完全に削除されます。

スニペットでは、物事はかなり単純ですが、クロージャを使い始めると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できるかを調べてみてください。

于 2012-10-17T09:54:03.423 に答える