11

全て!

LinkedBlockingQueue で奇妙なコードを見つけました:

private E dequeue() {
        // assert takeLock.isHeldByCurrentThread();
        Node<E> h = head;
        Node<E> first = h.next;
        h.next = h; // help GC
        head = first;
        E x = first.item;
        first.item = null;
        return x;
}

ローカル変数 h が必要な理由を誰が説明できますか? GC にどのように役立ちますか?

4

4 に答える 4

7

jsr166 srcを見ると、問題のあるコミットが見つかります。v1.51 までスクロールします。

これは、答えがこのバグレポートにあることを示しています

完全な議論は、jsr.166 メーリング リスト スレッドにあります。

「GC を支援する」ビットは、物事がテニュアに流れ込むのを避けることです。

于 2012-01-15T10:21:42.493 に答える
5

少し遅いかもしれませんが、現在の説明は私にとって完全に満足のいくものではなく、より賢明な説明が得られたと思います.

まず第一に、すべての Java GC は何らかの方法でルート セットから何らかのトレースを行います。これは、古いヘッドが収集された場合、nextとにかく変数を読み取らないことを意味します-そうする理由はありません。したがって、 IFヘッドは次の反復で収集されますが、問題ではありません。

上記の文の IF は、ここで重要な部分です。異なるものの隣に設定することの違いは、頭を収集すること自体には関係ありませんが、他のオブジェクトに違いをもたらす可能性があります。

単純な世代別 GC を想定してみましょう。head が若いセットにある場合、とにかく次の GC で収集されます。ただし、古いセットにある場合は、めったに発生しない完全な GC を実行したときにのみ収集されます。

ヘッドが古いセットにあり、若い GC を実行するとどうなるでしょうか? この場合、JVM は古いヒープ内のすべてのオブジェクトがまだ有効であると想定し、古いオブジェクトから若いオブジェクトへのすべての参照を若い GC のルート セットに追加します。そして、それはまさにここで割り当てが回避するものです: 古いヒープへの書き込みは、通常、JVM がそのような割り当てをキャッチして正しく処理できるように、書き込みバリアまたは何かで保護されますnext。結果があります。

短い例:

があると仮定します1 (old) -> 2 (young) -> 3 (xx)。ここでリストから 1 と 2 を削除すると、次の GC で両方の要素が収集されると予想できます。ただし、若い GC のみが発生しnext、古い GC のポインターを削除していない場合、要素 1 と 2 の両方が収集されません。これとは逆に、1 でポインターを削除した場合、2 は若い GC によって収集されます。

于 2012-01-14T03:44:13.413 に答える
0

質問を説明するコード サンプルを次に示します: http://pastebin.com/zTsLpUpq。後で GC を実行し、runWith()両方のバージョンのヒープ ダンプを取得すると、Item インスタンスが 1 つしかないことがわかります。

于 2012-01-11T15:37:05.820 に答える
0

何が起こるかをよりよく理解するために、コードを実行した後にリストがどのように見えるかを見てみましょう。まず最初のリストを考えてみましょう:

1 -> 2 -> 3

次に、およびをh指します。headfirsth.next

1 -> 2 -> 3
|    |
h    first

次にh.nexthおよび をhead指しfirstます:

1 -> 2 -> 3
|   / \
h head first

これで、実際には、最初の要素を指しているアクティブな参照のみがあることがわかります。これはそれ自体 ( h.next = h) であり、GC はアクティブな参照を持たないオブジェクトを収集することもわかっているため、メソッドが終了すると、(old)リストの先頭はh、メソッドのスコープ内にのみ存在するため、GC によって安全に収集できます。

firstそうは言っても、古典的なデキュー方法(つまり、単に make point tohead.nextheadpoint to first)を使用しても、古いヘッドを指す参照はもうないことが指摘されており、私もこれに同意します。ただし、このシナリオでは、古い頭はメモリ内にぶら下がったままになり、そのnextフィールドはまだ を指してfirstいますが、投稿したコードでは、それ自体を指している孤立したオブジェクトだけが残っています。これにより、GC の動作が速くなる可能性があります。

于 2012-01-11T12:51:14.567 に答える