- - PR -
ガベージコレクションの対象となるタイミングについて
| 投稿者 | 投稿内容 | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2003-11-17 19:03
String型は、参照していくのではなく、新たに領域を作成して同じ値とか、ものがはいるのではなかったでしたっけ?(記憶がうすく・・・、わすれかけ・・・また、こんな紛らわしいコードを開発中に書いていたら、周りから、とばっちりがきますね、きっと)となると、問題文の"ABC"の入っている領域は変数aで、b[0]には問題文では聞いていない同じ値でメモリの領域も異なる"ABC"が入っているのでは・・・。メモリの領域も実際の値も違うもので・・・。問題文からすると、聞いているのは"ABC"の入っているとしか記載されていないので、変数aがGCされることを聞いているのかと思いました。
Object型で確認をするのはちょっと難しいのでは・・・?。nullをいれての確認で、単位、System.gc()をいれても、デバッグはできないと思われます。また、変数の中の値をみても、この問題の確認をすることはできないと思います。GCはかなり高度にできています。だから、JAVAはCよりも、実際の開発中にバグが少なく、メモリにこだわりを持たずに楽に開発ができると思い・・・。問題文に"ABC"と記載するのではなく、変数aの内容がGCされるタイミングなんて記載したら、誰でも回答できる問題になってしまい・・・。いずれにせよ、開発をする際にはあまり関係のないところのように思われ。 私の勘違いであれば、申し訳なく、すいません。(^^; | ||||||||||||||||||||||||||||||||||||
|
投稿日時: 2003-11-17 20:15
ずっと何がおかしいのか悩んでいました。
a="ABC"としてaに"ABC"のポインタが格納し、 b[0]=a;とするとb[0]に「aのポインタ」が格納されるのではなく、 「aに格納されているポインタと同じメモリ領域を指す別のポインタ」が格納される。 よってaとbに格納されている物は同一の物ではなく、 a=null;としてもb[0]にはポインタが依然存在するので"ABC"はGCの対象にならず、 b[0]=null;とした時点で参照が無くなる為"ABC"はGCの対象になる。 というふうな理解でよろしいのでしょうか? (追記) 「メモリ領域」は「オブジェクト」、 「ポインタ」は「(オブジェクトへの)参照」と読み替えてくださいm(_ _)m [ メッセージ編集済み 編集者: moke 編集日時 2003-11-17 21:17 ] | ||||||||||||||||||||||||||||||||||||
|
投稿日時: 2003-11-17 20:57
僕もよくわからないんですけど、もしかして
b[0] = a; とやった時に、"ABC"というオブジェクトが新たに生成されて、b[0]には新しいオブジェクトへの参照が格納される・・・なんてことが起きていたとすれば現象面の説明はできますね。 ただし責任は持てません^^; | ||||||||||||||||||||||||||||||||||||
|
投稿日時: 2003-11-17 21:42
String型だろうがObject型だろうがどちらも同じ動きをしますよ。
3行目でString配列型のインスタンスが作成されて、それの参照がbに入ります。
次に4行目でString型のインスタンス("ABC")が作成されて、それの参照がaに入ります。
そして、5行目でb[0]がaのインスタンスを指すようになります。
この後6行目でa=nullとすると、変数aからString型インスタンス"ABC"は参照されなくなります。
7行目でb[0]からString型インスタンス"ABC"が参照されなくなります。
最後に8行目でbからString配列型インスタンスが参照されなくなります。
ここで問題となるのがガーベッジコレクションの対象となる条件ですが、 これは、スタック領域からたどれなくなったインスタンスが対象になります。 なので、6行目の時点では、aからはたどることは出来ませんが、bからたどることが出来るので、 ガーベッジコレクションの対象にはなりません。 次の7行目の時点でインスタンス"ABC"をスタック領域からたどれなくなるので、 ガーベッジコレクションの対象となります。 で、皆こう思っているので、2番目の問題が腑に落ちないと言っているんですよ。
CよりはJavaはメモリ管理の煩わしさはありませんが、 ぜんぜん考えないでいいということじゃないです。 ガーベッジコレクションの機能上スタック領域から辿れてしまうと、 生きているインスタンスだと判断されて、ずっとメモリ上に居座りつづけます。 こうなるとどうなるかは、参考文献を参照してください。 終(ふ〜) 参考文献:Java PRESS Vol.32 92ページ(今書店に並んでいるやつです。) | ||||||||||||||||||||||||||||||||||||
|
投稿日時: 2003-11-18 03:20
日本語での説明に限界を感じ・・・。
配列と参照と、ガーベッジコレクションと、そのほかにもいろいろとありますけど、説明にちと、ギブアップといった感じです。でも、これだけ、全員が同じ意見であれば、私の考えが間違っているのは間違いないでしょう。 試験対策の時にJAVAのソースコードをひっくり返して見返したときに何かを私は勘違いしてしまっ他のだと思います。それにコード内のGCは私レベルでは難しすぎて・・・。普通に考えている内容ととってもかけ離れているものだったので。 でも、下の図、なんか、配列を使用した参照の場合だと、おかしいような気がするのはわたしだけですかねぇ・・・。 | ||||||||||||||||||||||||||||||||||||
|
投稿日時: 2003-11-18 11:15
おそらく、出題者の意図としてはアティさんの説明のようなことなのでしょうが…
実際は、文字列リテラルはすべて文字列プールに格納され、ガベコレされることはありません。 (String#intern()の説明を参照) 問題1で、new String("Hello") としてわざわざ新たなStringオブジェクトを生成しているのは、 この制約から逃れるためでしょう。 問題2は、「出題者の間違い」というのが正解ではないかと。 | ||||||||||||||||||||||||||||||||||||
|
投稿日時: 2003-11-19 11:25
前に確認したときは教科書と実際の動きが違っていたので、なんとなく、確認してみたくなり、ちょっと、メモリを確認してみました。回答はb=nullの後ですね。みんな不正解のようです・・・。まだ、はっきりと断言できず、確認することがほかにもあるので、もう少し確認しようかと。ただ、コンパイラのバージョンにもよる感じがして、前に確認したときとも結果が異なっているような気がしますが、コンパイラーのバージョンを覚えておらず・・・。参考書には一律、皆さんが説明させた形で記載しているような感じがします。GCに関してはドキュメントにも明確に記載していることがなく、Sunがもしかしたら、後に変更するかもしれないので、このような形にしているのかもしれません。なので、もう少し、調べる必要があります。ただ、調べるにあたり、どなたか、変数の格納されているメモリアドレスをJAVAのメソッドで確認する方法をアドバイスもらえませんか?一応確認しているコードを乗せます。何か勘違いしている部分があったら教えていただきたく。(未熟者なのでお願いします)
Cを使用してNativeメソッドを使用してもいいのですが、面倒で・・・。 public class Sample { public static void main(String args[]){ Runtime rt = Runtime.getRuntime(); long l1 = 0L; String[] b = new String[1]; String a = "ABC"; b[0] = a; System.gc(); System.gc(); System.gc(); System.gc(); System.gc(); l1 = rt.freeMemory(); System.out.println("l1 : " + l1); a = null; System.gc(); System.gc(); System.gc(); System.gc(); System.gc(); l1 = rt.freeMemory(); System.out.println("l2 : " + l1); b[0] = null; System.gc(); System.gc(); System.gc(); System.gc(); System.gc(); System.gc(); System.gc(); System.gc(); System.gc(); System.gc(); l1 = rt.freeMemory(); System.out.println("l3 : " + l1); b = null; System.gc(); System.gc(); System.gc(); System.gc(); System.gc(); l1 = rt.freeMemory(); System.out.println("l4 : " + l1); System.out.println("Bye"); } } | ||||||||||||||||||||||||||||||||||||
|
投稿日時: 2003-11-19 11:50
unibon です。こんにちわ。
String を使わないようにしてみました。ちょっと長いですがぜんぶ載せます。
こうすると、結果は大別すると2通りあり、
の場合と、
の場合に分かれました。 System.out.println は内部で synchronized していますので、 表示は早い者勝ちだと思いますので、これから言えることは、 String クラスでなければ、 b[0] = null; と b = null; の間に finalize が動くこともありえる、 すなわち b = null; よりも早い時点でガーベッジコレクションが動くことがありえる、 と言えます。 もとの問題を厳密に捉えると対象は String クラスなので、 finalize を挟み込めませんので、分かりませんでした。 というか、Java においては String は特殊扱いのクラスなので、 初学者向けのサンプルや試験問題にはあまり取り上げないほうが良いのでは、 という気持ちを持っています。 | ||||||||||||||||||||||||||||||||||||
