- - PR -
ガベージコレクションの対象となるタイミングについて
| 投稿者 | 投稿内容 | ||||||||
|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2003-11-20 17:12
unibon です。こんにちわ。
あまりたいしたことではないのですが、 final なクラスなのに勝手にメソッド宣言に関する部分まで改造してしまうと VM の中で finalize をオーバライドしていないことを前提にしている箇所と 矛盾してしまうためなのかな、と今のところ思っています。 #既存のメソッドの中にコードを追加する分には構わないけど。 | ||||||||
|
投稿日時: 2003-11-20 18:23
ローカル変数stringで参照されいたのは"Test"のリテラルが示すStringオブジェクトであることは間違いないと思いますが...。 ちなみに、mainメソッド内などで"Test"というリテラルを使っていた場合や、class1, loader, objectのいずれかにnullを代入しなかった場合などはstringRefの参照先オブジェクトは解放されません。 | ||||||||
|
投稿日時: 2003-11-20 23:39
確かにWataさんの、
「クラスがアンロードされるまでだと思います。」が正しそうです。 ただ、「同一の文字リテラルを持つ全ての」を頭に加えたほうがいいかな。 | ||||||||
|
投稿日時: 2003-11-21 07:44
私もそう思います。java.lang.String#internのドキュメントに書いてあるように、文字プールはStringクラスが持っているもののはず。UnLoadedClassがアンロードされたからといって、文字プールの"Test"が消されたわけではありません。 Wataさんの例の string = null; だけをコメントアウトして、java -verbose:gc ClassUnloadTest で実行してみると、
という結果が出ます。これを見ると、UnLoadedClassがアンロードされているのにもかかわらず、文字リテラルは存在しています。前にも言いましたが、internされたStringオブジェクトはStringクラスがアンロード(VMが終了)するまでGCの対象にならないと思います。(とは言ったものの、あまりにもプールのサイズが大きくなったらどうするんだろう?) #私はガーベッジコレクションに一票。 | ||||||||
|
投稿日時: 2003-11-21 09:07
とっても気になったのでもうちょっと深く調べました。
「internされている文字列はGCの対象になるのか」 internされている文字列とは、コンパイル時に作られる文字列(クラスのロード時にプールされる)と実行時に明示的にinternされる事をさします。 "A pool of strings, initially empty, is maintained privately by the class String." とJava APIドキュメントに書いてあるので文字列プールはStringクラスが持っていることは間違いありません。クラスがロードされると、コンパイル時に用意されている文字列がプールに追加されます(言語仕様 12.5)。言語仕様 3.10.5より、これらの文字列はinternされていないといけません。実行時にinternを呼び出すと、プールに新しい文字列を追加し、プールにある文字列への参照を返します。 さて、一旦プールされた文字列がGCされるかどうかですが、Java言語仕様にも、JVM仕様にも、APIにもプールされたStringオブジェクトがGCの対象にされないとはどこにも書かれていません。そのため、JVMとAPIの実装によってはプールされている文字列もGCの対象になりえます。 実行時にinternされた文字列は、誰からも参照されなくなった時点で他のオブジェクト同様にGCの対象になりえます。クラスのロード時に追加された文字列はクラスがアンロードされて、かつ誰からも参照されなくなった時点でGCの対象になりえます。 つまり、私が前に言った「internされたStringオブジェクトはStringクラスがアンロード(VMが終了)するまでGCの対象にならない」は誤っています。 以上、Java Technology Forums (http://forum.java.sun.com/) の過去ログ(string poolで検索)で調べてきました。 さてさて、また話を蒸し返しますが、最初に忍者鳥取県さんが聞いた問題においては、"ABC"がコンパイル時に作られる文字列であるため、a = null; とした時にGCの対象になることは絶対にありえません。また、クラスがアンロードされるのがmainを抜けた後なので、b[0]=null; や b=null; としても"ABC"はまだGCの対象にはなりえません。 もし、String a = "ABC"; が String a = new String(new char[]{'A', 'B', 'C'}); a = a.intern(); となっていれば、プールされている"ABC"は b[0]=null; とした時点でGCの対象になりえます。
| ||||||||
|
投稿日時: 2003-11-21 09:43
すみません。そのとおり。省略してしまいました。 イメージ的には、Classオブジェクトが自クラス内で使用するリテラルのintern済みオブジェクトの参照を持っていると考えればよいのではないでしょうか? そしてinternされたオブジェクトも、全ての参照がなくなればGC対象となる。(プール内のオブジェクトも例外的な扱いはされない。)
おお!-verbose:gcオプションをつければクラスがアンロードされたかどうかはすぐわかるのですね。ちなみに、string = null;をしない場合は自明だと思ったので、説明を省いてしまいました。 | ||||||||
