为什么 System.gc() 用于并行,而 G1 则不减少 RSS?

Why isn't RSS reduced when System.gc() for parallel, but for G1 is?

提问人:Some Name 提问时间:11/17/2023 最后编辑:Some Name 更新时间:11/21/2023 访问量:37

问:

我正在使用 Java 17。我有一个 2GB 的容器并运行以下 Java 程序:

import java.util.*;

public class Main{
        public static Map<byte[], byte[]> m = new HashMap<>();

        public static void main(String args[]) throws Exception {
                int i = 0;
                while(true){
                        i++;
                        byte b[] = new byte[1024 * 1024];
                        m.put(b, b);
                        if(i % 700 == 0){
                                System.out.println("Reached limit: " + i);
                                m = new HashMap<>();
                                Thread.sleep(500000);
                                System.gc();
                                Thread.sleep(500000);
                        }
                }
        }
}

使用选项运行它

java -XX:+UseParallelGC \
     -XX:InitialRAMPercentage=40 \
     -XX:MaxRAMPercentage=40 \
     -XX:-ShrinkHeapInSteps \
     -XX:MinHeapFreeRatio=10 \
     -XX:MaxHeapFreeRatio=10 Main

我一直收到堆报告的 RSS 是 800MB,它并没有变低。pmap

     Address Perm   Offset Device   Inode    Size    Rss    Pss Referenced Anonymous 
    ccc00000 rw-p 00000000  00:00       0  839680 838812 838812     838812    838812       

但很明显,这是应用而不是忽略的:System.gc()

[5.871s][info ][gc             ] GC(4) Pause Full (System.gc()) 702M->1M(792M) 2.820ms

所以既没有也没有减少RSS。-XX:-ShrinkHeapInSteps -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=10 -XX:+UseParallelGCSystem.gc()

我需要减少 RSS,因为大多数时候 Java 堆必须很小,而且白白消耗这么多 RSS 是低效的。

值得注意的是,可以减少 G1 GC 的 RSS 量并按预期工作。System.gc()

有没有办法为并行做到这一点,为什么 G1 和简单的完整 GC 需要是不够的?System.gc()

Java 内存管理 JVM 垃圾回收 G1GC

评论

0赞 Mark Rotteveel 11/17/2023
Java 不一定将分配的内存返回给操作系统(这取决于垃圾回收器及其配置)。如果是这样,它通常不会立即这样做。
0赞 markspace 11/17/2023
I need the RSS to be reduced since most of the time Java heap must be small and it's simply inefficient我的观点恰恰相反。内存很便宜,工程时间很昂贵。你真的能证明这种说法的合理性吗?这里到底有什么效率低下?
0赞 Some Name 11/17/2023
@MarkRotteveel 所以即使这样的行为没有记录在案,我猜......G1GCSystem.gc()
0赞 Some Name 11/17/2023
@markspace 好吧,主机有 2GB 的物理内存。 进程使用了堆大小,但消耗了 RSSjava1MB800MB
1赞 Mark Rotteveel 11/17/2023
据我所知,并行 GC 无法将内存返回给操作系统(尽管我可能错了)。

答:

1赞 apangin 11/21/2023 #1

并行 GC 从不取消提交为 Java 堆保留的内存,而 G1 可能会取消提交未使用的内存(即将其返回给操作系统)。在 JDK 12 之前,G1 只能在完整的 GC 或并发周期后返回内存。从 JDK 12 开始,它可以更频繁地取消提交 - 有关详细信息,请参见 JEP 346

Смотритетакже: Java 进程的内存占用