私はのガベージ動作をプロファイリングしていますが、クラス内で初めてjava.lang.String
文字列をインスタンス化するたびに、常にガベージが生成されるようです。誰かが理由を知っていますか?
public abstract class AbstractTest {
protected static String SERGIO = "sergio";
private String someValue;
public void init() {
this.someValue = new String(SERGIO);
}
}
public class Test extends AbstractTest {
private static String JULIA = "julia";
private Runtime runtime = Runtime.getRuntime();
private String anotherValue;
private String yetAnother;
private void gc() throws InterruptedException {
System.gc();
Thread.sleep(100);
}
private long usedMemory() {
return runtime.maxMemory() - runtime.freeMemory();
}
public void test() throws Exception {
gc();
this.anotherValue = new String(SERGIO); // a bunch of garbage is created!
long usedMemory = usedMemory();
gc();
long usedMemoryAfterGC = usedMemory();
System.out.println("Collected: " + (usedMemory - usedMemoryAfterGC));
gc();
this.yetAnother = new String(JULIA); // no more garbage
usedMemory = usedMemory();
gc();
usedMemoryAfterGC = usedMemory();
System.out.println("Collected: " + (usedMemory - usedMemoryAfterGC));
}
public static void main(String[] args) throws Exception {
Test t = new Test();
t.test();
}
出力:
収集:704336
収集:0
それはいいです。最初にガベージを作成し、その後のインスタンス化ではガベージを生成しません。
奇妙なことに、スーパークラスで文字列を強制的に作成しても、サブクラスで文字列を最初にインスタンス化したときに、サブクラスでガベージが作成されます。
public void test() throws Exception {
gc();
init(); // creates a String in the superclass
gc();
this.yetAnother = new String(JULIA);
long usedMemory = usedMemory();
gc();
long usedMemoryAfterGC = usedMemory();
System.out.println("Collected: " + (usedMemory - usedMemoryAfterGC));
}
出力:
収集:348648
なぜですか?
(ちなみに、これはMACとJDK 1.6.0_37で実行しています)
編集1:コードを少し変更して、文字列の内部化がここでの原因ではないことを明確にしました。少なくとも、そうであるようには見えません。
EDIT2:コード全体でStringをObjectに変更すると、同じガベージが発生するため、Javaでnewを介したオブジェクトの割り当てがどのように行われるかに関係していると思います。クラスに初めてオブジェクトを割り当てると、ガベージが発生します。2回目はしません。奇妙なことに、クラスごとです。
EDIT3:上記のコードで行っているように、GCにガベージ作成のためにアプリケーションのプロファイルを強制する方法について説明するブログ記事を書きました。