java - 在 Java 中实例化对象时产生奇怪的垃圾

标签 java garbage-collection real-time low-latency

我正在分析 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 条

没关系。第一次创建垃圾,随后的实例化不会产生垃圾。

奇怪的是,当您在父类(super class)中强制创建字符串时,当您第一次在子类中实例化字符串时,它仍然会在子类中创建垃圾:

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:我稍微更改了代码,以明确字符串内化不是这里的罪魁祸首,至少看起来不是这样。

编辑2:如果在整个代码中将 String 更改为 Object,则会得到相同的垃圾,因此我猜这与 Java 中通过 new 进行对象分配的方式有关。第一次在类中分配对象时,您会得到垃圾。第二次你就不会了。奇怪的是每个类(class)

编辑3:我写了一个blog article我在其中讨论了如何强制 GC 分析您的应用程序以进行垃圾创建,就像我在上面的代码中所做的那样。

最佳答案

类中的文字字符串将在第一次引用时(如果不是之前)被“保留”。实习通常涉及丢弃字符串的原始版本并使用实习版本,并且在此过程中可能会创建和丢弃更多对象。

(当然,在没有特殊内部钩子(Hook)的情况下,确实没有可靠的方法来检测任何单个操作中生成了多少垃圾,因此您的测量充其量是值得怀疑的。)

关于java - 在 Java 中实例化对象时产生奇怪的垃圾,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13501942/

相关文章:

java - 仅在 SWT 而非 jface 中复制文件时显示进度栏

macos - 从 macOS 上的打开命令启动的应用程序进程获取 pid

.net - 我什么时候应该使用 IDisposable,使用它会不会出错?处置链呢?

隐藏阶段时的JavaFX 8内存泄漏

java实时优先级高于应有的优先级

java - 在回收者 View 中从 firebase 检索某些 key

java - 字符串在单元格中不完全可见

c# - 何时将对象返回到其池中

python - 使用 sklearn 获取实时数据

python - 将实时数据发送到 Django 前端