Java言語でのガベージコレクションと変数のスコープとの関係について教えてください。以下のプログラムをコンパイル/実行したところ、


mylist = 10
mylist = 110
mylist = 210
<<中略>>
mylist = 910

という結果になりました。変数tmpのスコープは最初のforループが終わったところなので、生成したインスタンスもそのときに破棄されると考えていたのですが、実行結果を見る限り違うようです。変数のスコープとガベージコレクションのタイミングは別と考えてよろしいのでしょうか?

できましたら、該当するJava言語仕様へのリンクも示していただければ嬉しいです。

以上、よろしくお願いします。

--- ソース ---
import java.util.*;

class sample {
 public static void main(String[] arg) {
  List<Integer> mylist = new ArrayList<Integer>();
  for( int i=0 ; i<10 ; i++ ){
   Integer tmp = new Integer(i*100+10);
   mylist.add(tmp);
  }
  for( int i=0 ; i<10 ; i++ ){
   System.out.println("mylist = " + mylist.get(i));
  }
 }
}

回答の条件
  • 1人2回まで
  • 登録:
  • 終了:2008/04/26 22:17:59
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:pahoo No.1

回答回数5960ベストアンサー獲得回数633

ポイント35pt

変数のスコープとガベージコレクションのタイミングは別と考えてよろしいのでしょうか?

別と考えていいでしょう。

実際にガベージ・コレクションがどのタイミングで発生しているかを知るには、JVMの -verbose:gc オプションを使って調べることができます。


Java の GC は、他言語に比べ、かなり複雑です。JVMの実装によって変わってくるのはもちろんのこと、CPU稼働状況によって変化するように設定することもできます。


仕様書として最も詳しいものは「Memory Management in the Java HotSpot. Virtual Machine」だと思うのですが、日本語版が出ているかどうかは分かりません。


参考サイト

id:miyohide

回答ありがとうございます。

なかなか複雑な仕組みなのですね。特に、「GCアルゴリズム詳細解説」は面白そうなサイトですね。頑張って読み進めてみます。

2008/04/26 22:11:23

その他の回答2件)

id:pahoo No.1

回答回数5960ベストアンサー獲得回数633ここでベストアンサー

ポイント35pt

変数のスコープとガベージコレクションのタイミングは別と考えてよろしいのでしょうか?

別と考えていいでしょう。

実際にガベージ・コレクションがどのタイミングで発生しているかを知るには、JVMの -verbose:gc オプションを使って調べることができます。


Java の GC は、他言語に比べ、かなり複雑です。JVMの実装によって変わってくるのはもちろんのこと、CPU稼働状況によって変化するように設定することもできます。


仕様書として最も詳しいものは「Memory Management in the Java HotSpot. Virtual Machine」だと思うのですが、日本語版が出ているかどうかは分かりません。


参考サイト

id:miyohide

回答ありがとうございます。

なかなか複雑な仕組みなのですね。特に、「GCアルゴリズム詳細解説」は面白そうなサイトですね。頑張って読み進めてみます。

2008/04/26 22:11:23
id:b-wind No.2

回答回数3344ベストアンサー獲得回数440

ポイント30pt

なにかいくつか誤解があるようです。

変数tmpのスコープは最初のforループが終わったところなので、生成したインスタンスもそのときに破棄される

変数 tmp のスコープは確かに for ループ内で完結しています。

ただ、生成したインスタンス(Integer)の生存期間は変数のスコープとは直接関係ありません。

(組み込み型である int なら変数のスコープ終了と同時に破棄されますが)

インスタンスが破棄される条件はそのインスタンスへのリファレンスが無くなったときです。

この場合、mylist.add() で mylist オブジェクトの中にリファレンスを格納しているのでオブジェクトは生存し続けます。


mylist オブジェクトが破棄された段階で初めて格納された各 Integer オブジェクトも破棄の条件を満たします。


また、オブジェクトが破棄の条件を満たすこととそれがガベージコレクションされることはまた別の話です。

Java の場合、通常のプロセスとはまったく別のところでガベージコレクタが動作しますので実際に

ガベージコレクションが行われるタイミングをコントロールすることは出来ません。

また、このプログラムの動作にガベージコレクションのタイミングは一切関係ないように思えます。

ガーベジコレクション

id:miyohide

回答ありがとうございます。

ご指摘の通り、プリミティブ型とごっちゃになったためかと思います。

2008/04/26 22:13:59
id:ken33jp No.3

回答回数928ベストアンサー獲得回数13

ポイント26pt

>変数のスコープとガベージコレクションのタイミングは別

別です。

GCは本来そういうものです。

オブジェクト=NULLと明示的に書けば、

ガベージコレクションの対象だとわかりやすいので、

JVMも助かります。

id:miyohide

回答ありがとうございます。

なるほど、本来そういうものなのですね。オブジェクト=NULLは覚えておきます。

2008/04/26 22:15:44
  • id:ujip
    すでに完結されていますが、この質問で示されたプログラムと出力結果に違和感を感じませんでした。
    なぜtmpがgcされてしまったと感じたのか教えていただけるとうれしいです。
    for(var i=0;i<10;i++)
    であれば、 iに代入されるのは0,1,2,3,4,5,6,7,8,9しかなく(((i<10)==true)の間しかforループは回らないので・・・)出力結果も10,110,,,,910で問題ないような気がしたのですが、
    出力結果を見て、GCが関係しているんじゃないかと疑問に思われたのはどうしてかなと、思った次第です。
  • id:miyohide
    >ujipさん
    コメントありがとうございます。うまく伝わるかは怪しいのですが(^▽^;)、答えてみます。
    tmpのスコープが外れる
    →スコープが外れるってことは破棄される(と思い込んでいた。プリミティブ型がそうなので。)から、ひょっとしたらGCの対象になるのではないか?
    →2回目のforループでmylistの値が読めているのはたまたまなのではないか?まだGCが起きていないために読めている?

    ということで質問させていただいた次第です。

    変数のスコープとGCを一緒に考えていたということとが勘違いの原因かと思います。

  • id:ujip
    了解しました。
    2回目のforループに入ったとき、前回のtmpが参照するオブジェクトがGCされてしまっても、2回目のforループでtmpが参照するオブジェクトが新たに生成されるので、一回目のforループのtmpが参照するオブジェクトのGCの有無は2回目のforループの実行には関係なくなると思います。
    また、tmpが参照するオブジェクトではなく、tmpという変数自体についても、1回目のtmpと2回目のtmpは別ものと考えたとしても、問題なく動作するはずですから(1ループ中でtmpという変数名自体に変更はないので)、やはり期待通りと言うかプログラムどおりの出力が得られると考えます。
    やっぱり突き詰めて考えると面白いですね。

この質問への反応(ブックマークコメント)

トラックバック

  • はてなで質問をしてみた はてなでJavaに関する質問をしてみました。(http://q.hatena.ne.jp/1209176680 ) ちょっとインスタンス生成について頭がごっちゃになってきたので、はてなのポイントを
「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません