Adw*_*mar 6 java garbage-collection g1gc java-11
喜欢读一些答案后,这个和JEP-346,我已经意识到,G1确实释放内存返回给操作系统。
然而,它是否将内存释放回操作系统,甚至到了当前内存使用量可能低于初始堆内存的程度(即在此 JEP 之前,在我的情况下为 JDK11)?
假设我有一个 Java 11 VM在RAM上运行Xms并Xmx设置为,但是我只消耗大约. G1 会向操作系统释放足够的内存吗?5GB8GB1GB
我没有在任何地方找到任何文件说 G1 仅限于释放Xms记住阈值。
我在生产中观察到这一点,MemAvailable 一直减少到一个点,然后在 GC 之后,它在 8GB 的盒子上跃升至接近 30-35%。所以我假设它正在释放内存,这就是 MemAvailable 跳回的原因。
另外,向操作系统释放内存到底是什么意思,它是调用 free/unmap 吗?
Eug*_*ene 14
注意:我已经删除了我以前的答案并研究了来源(也建立了我自己的JVM只是为了找出这个特定时刻),这是答案。
简短的回答
JVM 11 version(目前),当使堆变小时不会低于Xms。
长答案
绝对真理在源代码中。而这里是缩小堆与否的决定。下面几行,你可以看到如果我们输入那个if,就会有一个日志语句:
尝试堆收缩(Full GC 后容量高于最大所需容量)。
所以本质上,如果我们能理解两个参数:capacity_after_gc和maximum_desired_capacity- 我们就可以解开这个谜。一般来说,capacity_after_gc不是很容易掌握的东西;主要是因为这取决于有多少垃圾以及当前 GC 可以回收多少。为简单起见,我将编写一些不会产生任何垃圾的代码,以便该值保持不变。
在这种情况下,我们只需要了解maximum_desired_capacity.
上面几行,你可以看到这是计算为:
maximum_desired_capacity = MAX2(maximum_desired_capacity, min_heap_size);
Run Code Online (Sandbox Code Playgroud)
不幸的是,这就是它变得棘手的地方,因为要真正了解这些人体工程学是如何设置的,需要遵循和理解大量代码;特别是因为它们依赖于JVM已经开始的各种论点。
例如min_heap_size 设置为:
Run Code Online (Sandbox Code Playgroud)// If the minimum heap size has not been set (via -Xms), // synchronize with InitialHeapSize to avoid errors with the default value.
请注意,它们甚至指的-Xms是minimum;尽管文档说它是初始的. 您还可以注意到它进一步取决于另外两个属性:
reasonable_minimum , InitialHeapSize
Run Code Online (Sandbox Code Playgroud)
这将难以进一步解释;这就是为什么我不会。相反,我将向您展示一些简单的证明(我确实浏览了大部分代码......)
假设你有这个非常简单的代码:
public class HeapShrinkExpand {
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
Thread.sleep(500);
System.gc();
}
}
}
Run Code Online (Sandbox Code Playgroud)
我运行它:
-Xmx22g
-XX:InitialHeapSize=1g
"-Xlog:heap*=debug"
"-Xlog:gc*=debug"
"-Xlog:ergo*=debug"
Run Code Online (Sandbox Code Playgroud)
在日志中,我会看到:
[0.718s][debug][gc,ergo,heap ] GC(0) Attempt heap shrinking (capacity higher than max desired capacity after Full GC). Capacity: 1073741824B occupancy: 8388608B live: 1018816B maximum_desired_capacity: 27962026B (70 %)
[0.719s][debug][gc,ergo,heap ] GC(0) Shrink the heap. requested shrinking amount: 1045779798B aligned shrinking amount: 1044381696B attempted shrinking amount: 1044381696B
Run Code Online (Sandbox Code Playgroud)
这会告诉你一些关于需要多少收缩的统计数据,当前容量是多少等等。下一行将显示堆减少了多少,实际上:
[0.736s][debug][gc,ihop] GC(0) Target occupancy update: old: 1073741824B, new: 29360128B
Run Code Online (Sandbox Code Playgroud)
堆确实缩小了,缩小到大约29MB。
如果我添加一个 JVM 启动标志:-Xms10g,那些负责显示堆收缩到多少的 GC 日志;不会再出现了。
事实上,如果我自己运行JMV(启用一些日志记录),这两个值:capacity_after_gc和maximum_desired_capacity将始终具有相同的值;意味着if statement永远不会进入,堆永远不会低于-Xms。
我已经用 JDK-13 运行了相同的代码,虽然缩小的日志存在于那里(当-Xms作为参数给出时),底层堆仍然停留在-Xms. 我发现更有趣的是,在 下java-13,尝试运行:
-Xmx22g -Xms5g -XX:InitialHeapSize=1g
Run Code Online (Sandbox Code Playgroud)
将正确出错:
指定的最小和初始堆大小不兼容