这里的GC收集是什么?

8
这可能很基础,但我非常好奇。以下是代码片段和输出结果:
public class PlainSystemGC {

    public static void main(String ...strings) {

        System.out.println("Free Memory (Before GC): " + Runtime.getRuntime().freeMemory());

        System.gc();

        System.out.println("Free Memory (After GC): " + Runtime.getRuntime().freeMemory());
    }
}

并且输出

Free Memory (Before GC): 1859640
Free Memory (After GC): 1911768

我想了解在没有创建对象的情况下GC收集的是什么。

被释放的内存是什么?(而且只有52kb)


@JSauer-即使运行100次,它也会给出完全相同的结果。


它并不总是相同的:http://ideone.com/5UkgE(122416已释放) - NullUserException
@NullUserExeception - 在不同的JVMS上释放的内存量可能会有所不同,但在相同代码的不同运行中,释放的数量将是相同的。 - JWhiz
1个回答

9
在大多数JVM实现中,main方法实际上并不是在JVM启动期间运行的第一段Java代码。
通常,完整JRE的许多部分本身都是用Java实现的。例如,类加载机制的大部分是纯Java实现的。甚至可能会在Java中编写垃圾回收算法的某些部分。
因此,即使您的应用程序根本没有创建任何垃圾,gc也可以收集那些系统类中已有的一些垃圾。
顺便说一句,在调用System.gc()时,您的应用程序至少会创建一个对象,该对象对于垃圾回收是可回收的:提到可用内存的String是动态构建的,而不是保存在变量中的,所以在System.gc()调用期间它可能会被gc。

此外,使用静态字段可能会导致类初始化代码的运行。例如,如果在 main() 方法之前尚未初始化 System 类,则使用 System.out 会导致其被初始化。请参阅语言规范 http://java.sun.com/docs/books/jls/third_edition/html/execution.html#44557。 - Andy Thomas
1
我怀疑在 System.out 中使用的 String 不会被垃圾回收。即使它没有被保存在变量中,由于它是一个字面量,因此它被 String 类保留。 - samitgaur
@Joachim Sauer - 我认为samG是正确的。由于它是一个字面量,可能无法被垃圾回收器回收。 - JWhiz
@Joachim - 我怎么会错过那个连接(长时间工作的缘故?)。实际上,那里不仅创建了一个String对象,还有一个StringBuilder对象,它将被标记为可回收垃圾。 - samitgaur
1
@JWhiz:指出这一点没问题,很好。由于每个字符串拼接(不会导致编译时常量)都将被编译器转换为对StringBuilder的调用,因此StringBuilder进入了图片中(早期的Java版本使用了StringBuffer,但除此之外,它的工作方式相同):JLS#15.18.1.2字符串连接优化 - Joachim Sauer
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接