为什么在这个示例程序中,OpenJDK 11的Java垃圾收集器会 *减少* 自由内存?

7
当我使用OpenJDK 11(Zulu分发版在Windows 10上)编译并运行以下非常简单的Java程序时:
public class GCTest {
    public static void main(String[] args) {
        System.out.println("Free memory before garbage collection: " + Runtime.getRuntime().freeMemory());
        Runtime.getRuntime().gc();
        System.out.println("Free memory  after garbage collection: " + Runtime.getRuntime().freeMemory());
    }
}

看起来垃圾收集正在减少可用内存的数量:

Free memory before garbage collection: 266881496
Free memory  after garbage collection: 7772200

这种情况在我使用Oracle的Java 8运行时不会发生。
Free memory before garbage collection: 254741016
Free memory  after garbage collection: 255795064

为什么会这样呢?

这是一个巨大的降幅。也许JDK决定可以将内存返回给操作系统?到目前为止它还没有这样做,但也许Java 11改变了这一点? - Thilo
显然,G1收集器会这样做,而Java 12也将更加积极地处理它。https://dev59.com/VF0a5IYBdhLWcg3wVHXU - Thilo
2个回答

14
答案是: 当显式调用时(例如通过System.gc()),Java 11的垃圾收集器可以减少Java进程(在Java中称为totalMemory)使用的内存。
在Java 8中, 默认垃圾收集器不能减少Java进程使用的内存。 Java进程占用的内存永远不会被释放。只有当您切换到G1GC垃圾收集器(选项'-XX:+UseG1GC')时,Java 8才能减少Java进程的使用内存(如果手动调用System.gc())。
“空闲内存”是Java进程占用但当前未使用的内存。因此,如果执行垃圾收集并减少Java占用的内存,则空闲内存量也会减少。
因此,计算Java进程的“空闲内存”的常见方法是使用
Runtime r = Runtime.getRuntime();
long free = r.maxMemory() - r.totalMemory() + r.freeMemory();
这种方法与Java进程当前占用的内存无关。

1
请注意,如果没有配置显式限制,则 maxMemory() 可能返回 Long.MAX_VALUE。在这种情况下,将应用进程的操作系统限制。 - Holger

2
我认为你所看到的是JDK决定你的堆对应应用程序的需求过大,因此将其返回给操作系统的块,从而减少了Java堆大小,并作为副作用也减少了空闲堆内存。"最初的回答"

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