2012-01-11 16 views
11

すべて!java.util.concurrent.LinkedBlockingQueueの奇妙なコード

私は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; 
} 

を? GCのためにどのように役立つでしょうか?

+0

多分コメントが古いされます(バージョン管理を見つけて、コミットにコメントを追跡することができますか?):) – milan

+2

それは、この一時varとコメントのみで追加されたことは興味深いですそれで、それは確かにいくつかの意図によって行われました。 http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/LinkedBlockingQueue.java#LinkedBlockingQueue.extract%28%29およびhttp: /grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/util/concurrent/LinkedBlockingQueue.java#LinkedBlockingQueue.dequeue%28%29 – Vadzim

+0

これは、openjdk、OracleのLinkedBlockingQueueです。 Mac(1.6.0_29-b11-402.jdk)のjdk 6には一時変数があります。 – milan

答えて

1

コードが実行された後にどのようにリストがどのように見えるかをよく理解してください。 headh.nextからfirst

1 -> 2 -> 3 

その後hポイント:

1 -> 2 -> 3 
| | 
h first 

firstからhheadポイントに続いてh.nextポイント:今すぐ

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

、まず最初のリストを考えます実際に我々はth ereはそれ自身である最初の要素(h.next = h)を指すアクティブな参照のみであり、GCはアクティブな参照がないオブジェクトを収集することもわかっているので、メソッドが終了すると、リストcaの(古い)先頭hがメソッドのスコープ内にのみ存在するので、GCによって安全に収集されます。古い頭の方を向いての参照がなくなったとしても、古典的なデキュー方法で(つまりはただfirsthead.nextheadポイントにfirstポイントを作る)こと、

これを言って、それを指摘された、と私はこれに同意します。しかし、このシナリオでは、古いヘッドはメモリにぶら下がっていて、firstを指しているnextフィールドを持っていますが、投稿したコードでは、孤立したオブジェクトが自分自身を指しています。これにより、GCがより速く動作するようになる可能性があります。

+0

'h.next = h'がなくても、下降原因hはもはや参照を持たないでしょう。 – Vadzim

+1

@Vadzim:私はそれを述べていませんでした。私は彼が投稿したコードで何が起こるかを説明していました。 – Tudor

+0

質問はそれに関するものではありません。それはなぜ 'first = head = head.next'だけではないのでしょうか。とにかくグラフィックスに感謝します。頭には常に最初のアイテム自体が含まれていないことに注意してください。 – Vadzim

0

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

+0

したがって、GCの "ヘルプ"とは何ですか? – Vadzim

+0

多分いくつかのシナリオでは、私は、おそらく私たちはコメントを書いた人を見つけることができるか分からない:) – milan

4

多分少し遅れているかもしれませんが、現在の説明は私にとっては完全に不満であり、私はもっと賢明な説明をしていると思います。

まず、すべてのJava GCは、ルートセットから何らかの種類のトレースを行います。つまり、古いヘッドが収集された場合は、next変数を読み取ることはありません。その理由は何もありません。したがって、IF頭は次の反復で収集されても問題はありません。

ここで、上記のIFが重要な部分です。異なる設定の次の設定の違いは、ヘッド自体の収集には関係ありませんが、他のオブジェクトには違いが生じる場合があります。

単純な世代GCを仮定しましょう。ヘッドが若いセットにある場合、それは次のGCで収集されます。しかし、それが古いセットに含まれている場合、まれに起こる完全なGCを実行したときにのみ収集されます。

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

ショート例:

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

+0

私は本当にあなたが言っているものと私が言ったものの間にどのような違いが表示されません。私はまた、次を削除しないと、GCがヘッドをより速く収集する可能性があると言いました。 – Tudor

+1

@ Tudorどのようなメカニズムが動作の変化を引き起こし、どのような状況で起こるかについて説明しました。これは、「何かがGCの動作を異なるものにする可能性がある」よりもはるかに重要です。また、頭が早く収集されるのではなく(それは明らかにナンセンスなので)、それ以降の要素については別のものがあります。 – Voo

+0

私のコメントでは、実際の実装がない場合、私はその割り当てがするべきものについてしか推測できないと述べました。一方で、あなたは、実際にそれらを導入することなく、「若いGC」のようなソースと使用された用語を実際に提供することなく、かなりの数の絶対的なステートメントを作成しました。 – Tudor

6

あなたはjsr166のSRCを見れば、あなたは問題が

http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concurrent/LinkedBlockingQueue.java?view=log を犯すでしょう(V 1.51を参照してください)

これは、答えは、このバグレポート

http://bugs.sun.com/view_bug.do?bug_id=6805775

十分な議論は、このスレッドであるであることを示している

http://thread.gmane.org/gmane.comp.java.jsr.166-concurrency/5758

「助けGC」のビットが殿堂入りへの出血の事を回避についてです。

乾杯

マット