【发布时间】:2012-11-21 20:55:10
【问题描述】:
我正在分析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 上运行它)
EDIT1:我稍微修改了代码以明确字符串内部化不是这里的罪魁祸首,至少看起来不像。
EDIT2: 如果在整个代码中将 String 更改为 Object,则会得到相同的垃圾,所以我猜这与 Java 中通过 new 进行对象分配的方式有关.第一次在类中分配对象时,您会得到垃圾。第二次你没有。奇怪的是每个班级。
EDIT3:我写了一个blog article,我在其中讨论了如何强制 GC 分析您的应用程序以创建垃圾,就像我在上面的代码中所做的那样。
【问题讨论】:
-
可能值得注意的是调用 System.gc();不保证垃圾收集器会立即运行。它有点像“嘿,如果你有机会,如果你能跑就好了”
-
不明白你所说的“垃圾”是什么意思——你期待什么?
-
garbage = 最终将由 gc 收集的堆中已取消引用的对象。如果你注意到了,我不是产生垃圾的人,而是 JVM 在幕后做的。 JDK 类经常这样做,但这次看起来有点奇怪。
-
@user489041 他在 System.gc() 之后正在睡觉,所以 GC 很有可能会运行。看起来是因为正在收集东西......难道 freeMemory() 只是以某种方式损坏了吗?
-
@TomaszNurkiewicz:这会导致它被汇集。所以它对性能很重要。但我不认为这是这个问题的问题
标签: java garbage-collection real-time low-latency