我正在分析垃圾行为,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
没关系。第一次它创建垃圾,然后后续实例化不产生垃圾。
奇怪的是,当您在超类中强制创建字符串时,它仍然会在您第一次在子类中实例化 String 时在子类中创建垃圾:
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:我写了一篇博客文章,其中讨论了如何强制 GC 分析您的应用程序以进行垃圾创建,就像我在上面的代码中所做的那样。