- PR -

ガベージコレクションの対象となるタイミングについて

投稿者投稿内容
begood
ベテラン
会議室デビュー日: 2003/09/12
投稿数: 97
お住まい・勤務地: とうきょー
投稿日時: 2003-11-19 22:35
解決しました。いろいろとご迷惑おかけし、申し訳なく。回答はガーベッジコレクトにキューされませんでした。今回はいろいろと勉強になった部分があり、感謝いたします。
とりあえず、確認コードを下記にのせておきます。

import java.lang.ref.*;

public class Sample{
public static void main(String args[]){
/*
Object[] b = new Object[1];
Object a = new Object();
*/
String[] b = new String[1];
String a = new String("ABC");


b[0] = a;
ReferenceQueue aReferenceQueue = new ReferenceQueue();
WeakReference ref = new WeakReference(a, aReferenceQueue);
boolean bool = ref.isEnqueued();
System.out.println("bool 1 : " + bool);


a = null;
System.gc();
bool = ref.isEnqueued();
System.out.println("bool 2 : " + bool);

b[0] = null;
System.gc();
bool = ref.isEnqueued();
System.out.println("bool 3 : " + bool);

b = null;
System.gc();
bool = ref.isEnqueued();
System.out.println("bool 4 : " + bool);

System.out.println("Bye");
}
}


[ メッセージ編集済み 編集者: begood 編集日時 2003-11-19 22:56 ]
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2003-11-19 23:23
unibon です。こんにちわ。

引用:

Wataさんの書き込み (2003-11-19 13:00) より:
Stringだとfinalizeがオーバーライドできないと言う事なので、弱参照を使ってみました。


なるほど。弱参照を使えば確認できるんですね。

なお、その後、String の finalize をオーバライド(String で Object.finalize をオーバライド)するために、
「例外処理Exception につて」
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=6544&forum=12
のように rt.jar を書き換えてみましたが、
String クラスに finalize メソッドを追加したものを実行すると
native な部分で落ちてしまい、ダメでした。

ちなみに String クラスのコンストラクタを書き換えて
デバッグ用に System.out.println を追加したものなら動きましたが、
でもリテラルはコンストラクタが動かないようでした。
たとえば、
コード:
class Foo {

    public static void main(String[] args) {
        String a = "unibon";
        String b = new String("unibon");
    }
}


では String b = new String("unibon"); の行ならコンストラクタが動きましたが、
String a = "unibon"; だと動きませんでした。
これってあたりまえのことなのかもしれませんが
(言語仕様書を見ていないので良く分からないのですが)。
コンストラクタが動かないのなら、
ガーベッジコレクションの対象にもならないのもなんとなく納得できます。
#ちなみに String クラスはコンストラクタの数が多すぎ。
Keisuke
大ベテラン
会議室デビュー日: 2003/10/24
投稿数: 105
投稿日時: 2003-11-20 03:58
引用:

引用:

なお、文字リテラルが開放されることがないというのは、JVMを終了させるまで開放されることはないということですか?


クラスがアンロードされるまでだと思います。


等しい文字リテラルは、クラスが異なっても同じインスタンスを指すので、
VM が終了するまで開放されないはずです。

H2
ぬし
会議室デビュー日: 2001/09/06
投稿数: 586
お住まい・勤務地: 港
投稿日時: 2003-11-20 07:22
引用:

unibonさんの書き込み (2003-11-19 23:23) より:
では String b = new String("unibon"); の行ならコンストラクタが動きましたが、
String a = "unibon"; だと動きませんでした。
これってあたりまえのことなのかもしれませんが
(言語仕様書を見ていないので良く分からないのですが)。
コンストラクタが動かないのなら、
ガーベッジコレクションの対象にもならないのもなんとなく納得できます。


「Java Language Specification - 3.10.5 String Literals」を参照のこと。String a = "unibon";はすでにコンパイル時にプールされてしまいますので、実行時には生成されないはずです。

元々の問題を見ると String a = "ABC"; とあるので、コンパイル時に"ABC"はプールされます。プールの生存期間はStringクラスがアンロードされるまで(現実的にはVM終了まで)なので、明らかに問題は間違っています。答えは、「プログラム終了するまで消されない」だと思います。

参考:
「Tech Tips 1999 1月14日」- http://sdc.sun.co.jp/java/private/techtips/1999/tt0114.html#3 (登録が必要)
「Java Language Specification - 3.10.5 String Literals」- http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html#101083 (英語)
「Java API Document − Stringクラス」

Wata
ぬし
会議室デビュー日: 2003/05/17
投稿数: 279
投稿日時: 2003-11-20 16:06
引用:

等しい文字リテラルは、クラスが異なっても同じインスタンスを指すので、
VM が終了するまで開放されないはずです。



一応、反証コードを挙げます。
まず、以下のようなコードをコンパイルし、クラスパスの通っていない場所にクラスファイルを配置します。
toString()の戻り値はリテラル文字列です。
コード:
public class UnLoadedClass {
   public String toString() {
      return "Test";
   }
}



次に、以下のようなクラスを作成しコンパイル実行します。
(1)のURLに上のクラスの格納ディレクトリのパスを指定してください。
(2)は作成したクラスローダーからクラスが読み込まれたことの確認です。
(3)はStringオブジェクトがリテラル文字列であることの確認です。
コード:
import java.lang.ref.WeakReference;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
public class ClassUnloadTest {

   public static void main(String[] args)
      throws
         ClassNotFoundException,
         InstantiationException,
         IllegalAccessException,
         MalformedURLException {

      // URLクラスローダーを使ってクラスを読み込む
      URLClassLoader loader =
         new URLClassLoader(
            new URL[] { new URL("file:///D:/hogehoge/")},		// (1)
            ClassUnloadTest.class.getClassLoader());
      
      Class class1 = loader.loadClass("UnLoadedClass");
      Object object = class1.newInstance();
      String string = object.toString();
      
      System.out.println("Is this Class loaded from my ClassLoader? "  
         + (class1.getClassLoader() == loader));			// (2)
      System.out.println("Is this String an interned string? " 
         + (string == string.intern()));					// (3)
      
      // 弱参照を保持する
      WeakReference classRef = new WeakReference(class1);
      WeakReference loaderRef = new WeakReference(loader);
      WeakReference objectRef = new WeakReference(object);
      WeakReference stringRef = new WeakReference(string);
      
      // 参照にnullを代入する
      loader = null;
      class1 = null;
      object = null;
      string = null;

      executeGC(classRef, loaderRef, objectRef, stringRef);
   }

   // GCを実行、状態を表示  
   private static void executeGC(
      WeakReference classRef,
      WeakReference loaderRef,
      WeakReference objectRef,
      WeakReference stringRef) {

      System.out.println();
      
      System.gc();
      System.out.println("GC executed!");

      System.out.println("ClassLoader : " + loaderRef.get());
      System.out.println("Class : " + classRef.get());
      System.out.println("Object : " + objectRef.get());
      System.out.println("String : " + stringRef.get());
   }
}



私の環境(Win2000、j2sdk1.4.2)では以下の出力が得られました。
ClassLoader : null
Class : null
Object : null
String : null
これはリテラル文字列もGCの対象であることを示すと思います。
まあ、現実的にクラスがアンロードされることなんて滅多にないと思いますけどね。
かずくん
ぬし
会議室デビュー日: 2003/01/08
投稿数: 759
お住まい・勤務地: 太陽系第三惑星
投稿日時: 2003-11-20 16:44
おふとぴー。

ところで、ガベージコレクションで正しいの、ガーベッジコレクションじゃなくて。

Googleの検索結果
ガベージコレクション 7730件
ガーベッジコレクション 1810件

ガベージコレクションの方が正しいのかな。はてな。

# 追加
つづりはgarbageなんすけど。

[ メッセージ編集済み 編集者: かずくん 編集日時 2003-11-20 16:49 ]
びしばし
大ベテラン
会議室デビュー日: 2002/03/13
投稿数: 181
投稿日時: 2003-11-20 16:54
Wataさんの例は、string というオブジェクトが gc されることを示すだけで、"Test" が gc されるかどうかは示していないと思います。


>ところで、ガベージコレクションで正しいの、ガーベッジコレクションじゃなくて。

こちらの発音記号を読んでください。音声でも確認できます。
http://dictionary.goo.ne.jp/search.php?MT=garbage&kind=ej

カタカナにするときに微妙に表記が発音とずれることはよくあることですね。
忍者鳥取県
ベテラン
会議室デビュー日: 2003/08/28
投稿数: 61
お住まい・勤務地: リオネジャネイロの地下6000Km
投稿日時: 2003-11-20 17:06
引用:

かずくんさんの書き込み (2003-11-20 16:44) より:
おふとぴー。

ところで、ガベージコレクションで正しいの、ガーベッジコレクションじゃなくて。

Googleの検索結果
ガベージコレクション 7730件
ガーベッジコレクション 1810件

ガベージコレクションの方が正しいのかな。はてな。

# 追加
つづりはgarbageなんすけど。

[ メッセージ編集済み 編集者: かずくん 編集日時 2003-11-20 16:49 ]



  このスレッド立てた忍者鳥取県です。
 色々みなさまにコメントを頂いているのですが、
 内容が難しすぎて全くリアクションができません。
 申し訳ありません。m(_ _)mペコリンコ
 しかし、色々と助言頂きまことにありがとうございます。
 (ちなみに、問題2を作成した会社へ問合せしてみましたが、
  依然回答は頂いておりません。)

 かずくんさんへ

 http://dictionary.goo.ne.jp/search.php?MT=garbage&kind=jn&mode=0&ej.x=45&ej.y=6

 こちらで本場の発音体験してみたください。
 どうも、本場の発音で言ったらガーベッジが正解っぽい
 すね。

スキルアップ/キャリアアップ(JOB@IT)