2017-09-18 18 views
12

Nicholas Zakasの本で、Javascriptでガベージコレクションの参照カウントを使用するときの循環参照の問題について説明します。 2つのオブジェクトが、彼らは関数の内部でそれらの2つの参照を持っているので、それらに割り当てられたメモリが解放されていないことを説明するJavascript参照カウントの円参照

function problem(){ 
    var objectA = new Object(); 
    var objectB = new Object(); 

    objectA.someOtherObject = objectB; 
    objectB.anotherObject = objectA; 
} 

:彼は、次の例を使用しています。私はこれがどのように機能するかを明確にしたいと思います。

明らかに、各オブジェクトには2つの参照があります。最初のオブジェクトはobjectAobjectB.anotherObjectの両方を指しています。したがって、各オブジェクトの参照カウントは2です。しかし、関数が終了するとどうなりますか?これは実際に本には書かれていません。彼は、参照カウントは、その値への参照が別の値で上書きされるたびに減少すると言います。私はこれが意味すると思います:

function problem(){ 
    var objectA = new Object(); 
    var objectB = new Object(); 

    objectA.someOtherObject = objectB; 
    objectB.anotherObject = objectA; 
    objectA.someOtherObject = objectA; //<-- that if I were to do this, 
             //the reference count of the first object (A) 
             //would become 3, and 1 for the second object (B). 

} 

しかし、関数が終了するとどうなりますか?私が理解する限り、objectAobjectBとそれらをそれぞれ参照するそれぞれのプロパティは破壊されるので、2つのオブジェクトの参照カウントは2ずつ減少します。私はZakasの "循環参照の問題"について話す。彼が何を言おうとしているのか、誰かが説明できるのだろうか?

答えて

11

私が理解する限り、objectAとobjectBの両方と、それぞれを参照するそれぞれのプロパティは破棄されます。 (関数スコープが終了しているため、ノークロージャはこれらの変数を参照しない)

ローカル変数objectAobjectBが破壊されます。つまり、変数によって参照されたオブジェクトの参照カウントは、それぞれで減分されます。

オブジェクトの参照カウントが0の場合、オブジェクトは破壊され、参照する他のすべてのオブジェクトはカウントが減少します。しかし、オブジェクトの数は依然としてそれぞれ1であり、それらは依然としてお互いを参照しており、何も破壊されることはありません。

+0

まだ参照カウントに依存している実装はありますか? https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Managementによると、これらのオブジェクト*はすべての最新の実装では破棄されます。 – rici

+0

@riciいいえ、参照カウントは、少なくともその素朴な形では、この欠点と[改善が必要]のために正確には使用されません(https://en.wikipedia.org/wiki/Reference_counting#Dealing_with_reference_cycles)。 MDNが述べるように、現代のすべてのエンジンは、いくつかのマークアンドスイープの実装を使用しています。しかしながら、単純化のためにより良い性能を発揮する可能性がある場合には、それほど循環していないかまたはそれほど循環していないことが知られている特定の局所構造にも、参照カウントを適用することができる。 – Bergi

+1

ええ、それは私が思ったことです。私はMSIEの初期のバージョンがこの問題に悩まされていたと思うので、OPに記載されている本はやや古いと思います。しかし、私の印象は、現代のES実装は、この例では両方のオブジェクトを正しくガベージコレクションすることです。質問は、参照カウントされた環境で循環参照の問題を説明することであることを理解していますが、問題が実際には存在しなくなったという回答には必ず言及する価値があります。参照サイクルを手作業で壊す必要はありませんが、あなたは依然として浮動しているアドバイスとは異なります。 – rici

10

参照カウントと「循環」参照の「問題」は、割り当てられたオブジェクトが他のオブジェクトへの参照を含む場合に発生しますが、それ以外の場合はアクティブな割り当てによって参照されません。すなわち、アクティブではないが他の非アクティブ項目への参照を含む項目の全体的な参照グラフにクリークが存在する。その関数は、2つの割り当てられたオブジェクトへのアクティブ参照がないから出ますが、参照カウントが0のローカル変数objectAobjectBがで消えてしまうではありませんので、オブジェクトがお互いを参照するあなたのコード例で

、 (その時点でクロージャ自体がガーベジであるため)、オブジェクトが保持する内部参照は参照カウントをゼロより大きく保ちます。

これは解決できない問題ではありませんが、ガベージコレクション手法として参照カウントを使用するという単純な方法が複雑になります。

JavaScriptの実装では、特定のガーベジコレクション手法を使用することを主張する規則や仕様はありません。

+0

ありがとうございました。もう1つの質問: 'objectA'と' objectB'が破壊された場合、それらの基礎となるプロパティーはどのように破壊されないのでしょうか?私はローカル変数(リファレンスですか?)をメモリ内の実際のオブジェクトと混同していますか? – Sahand

+2

* variables * 'objectA'と' objectB'は破壊されます。ローカル変数は、関数が呼び出されたときに作成される "シャドウ"オブジェクトのプロパティと考えることができます。関数が終了すると、そのオブジェクトはそのオブジェクトへの参照を持たず、そのプロパティはなくなります。つまり、ローカル変数によって参照されるオブジェクト*は、参照カウントが1だけ減少するということです。 – Pointy

+2

「クリークがあります...」 - 代わりに「サイクル」を意味しますか?クリーク(完全な部分グラフ)は問題を明示しますが、それらは必要ではありません。 – chi

関連する問題