为什么强制执行垃圾回收会增加Java进程分配的内存?

3

我有这段代码:

public static void main(String[] args) throws Exception {
    Thread.sleep(5000);
    System.out.println("Creating array...");
    Integer[] integers = new Integer[Integer.MAX_VALUE/32];
    Thread.sleep(5000);
    System.out.println("Destroying array");
    integers = null;
    //System.gc ();
    //System.runFinalization ();
    Thread.sleep(60000);
}

当我运行这段代码后,大约5秒钟后,我将在活动监视器中看到分配给Java进程的内存为268 MB。
当我取消注释(System.gc和其后面的一行)后,在控制台中看到“Destroying array”后,分配的内存增加到278 MB。
我可以理解,内存没有被释放,因为System.gc()只是一个JVM的提示,但是为什么会增加10MB?在这个时刻已经加载了什么到内存中?
2个回答

0

分配的内存并不一定意味着对象占用了内存。它可以是空闲的堆空间。

Java GC 是复制/压缩收集器,为了使复制工作正常运行,它们需要一些 TO 空间作为非垃圾的复制目标。

通过强制进行垃圾回收,您正在干扰 GC 的启发式算法,例如其暂停时间目标或吞吐量目标。为了补偿这一点,它可能会决定给自己更多的喘息时间 - 在配置的最大堆大小范围内 - 以仍然满足这些目标。

我不知道是否适用于所有 GC 算法,但使用 -XX:+PrintAdaptiveSizePolicy 记录可能会提供一些见解。


它并不强制进行垃圾回收。 - Dave Newton
我没有声明它这样做。 - the8472
“…并通过强制进行垃圾回收”?我猜我们对“强制”有不同的定义。 - Dave Newton
JVM的实现不一定要遵守它。例如,System.gc()可以通过命令行标志禁用。但一般来说,在那些配置下(即hotspot的默认配置),System.gc()不是一个noop,它会在本来不会发生GC的时候强制进行GC。一件事是实现允许做什么,另一件事是实现在正常情况下实际上如何行为。 - the8472
因此,“force”一词的使用是错误的,因为JLS明确规定您不能强制进行GC。我的观点是,OP正确地指出这是一个提示,你也承认了,然后你回答好像它被强制执行了一样。即使实现确实触发GC,它仍然在基本上任意的时间发生。我不喜欢在规范之外使用语言,因为这是误导性的,特别是因为有多个实现在野外广泛使用。 - Dave Newton
规范说明这只是一个提示。但是调用System.gc()的操作总是会导致反应(未安排的GC),这是一种有效的实现方式。因此,在实际实现中,它可以并且确实等同于强制执行GC(参见牛顿)。你所做的是描述基于原理图构建的机械系统。我在这里看到的是实际系统。只是不同的观点。无论如何,这对我的答案并不重要,只是争论语义。 - the8472

-1

你正在提出一个无效的问题。

你不能强制执行 GC,任何内存消耗都是完全实现细节。JVM 可以做很多事情,所以这个问题是完全无效的。

在不同的机器和 JVM 上,它的行为可能会有所不同。


问这个问题并不无效,而且它是可以回答的,尽管答案取决于JVM、操作系统、架构等因素。 - Dave Newton
这很有趣,但我不想玩文字游戏。 - Crazyjavahacking

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