java 垃圾收集器不会自行释放内存

toiithl6  于 2023-03-11  发布在  Java
关注(0)|答案(2)|浏览(141)

为什么我的垃圾收集器(G1GC)不释放内存,尽管他可以?使用的堆是随着时间的推移上升,在结束时下降的步骤是因为我强迫GC通过jcmd <pid> GC.run释放内存
为什么?这是正常行为吗?
我使用这些参数-Xms64m -Xmx256m -XX:G1ReservePercent=50启动GC

yvt65v4c

yvt65v4c1#

这张图看起来很正常。
G1 GC是一个分代收集器,这意味着堆被分为(在本例中)2代:新代和旧代。新代比旧代更频繁地被收集。在许多新代收集之后幸存下来的对象被“提升”到旧代。新代相对较小,并且频繁地被GC。旧代较大,但仅在其开始变满时才被GC。
因此......该图显示了一系列与新一代收集对应的“精细”锯齿。随着幸存对象被提升到旧一代,该线呈上升趋势。旧一代收集没有运行......因为JVM还没有计算出旧一代已满到足以保证收集。
然后,调用jcmd <pid> GC.run,这触发了一个老一代的内存回收,并收回了大约10 MB的内存(您不需要这样做,提前释放内存除了改变图表之外没有任何作用)。
然后,新的收集模式又恢复了。
问:这正常吗?
答:是的。
问:这里有问题吗?
答:没有证据表明有问题。当然不是GC本身的问题。您的应用程序可能有内存泄漏,但没有明确的证据表明有这样或那样的问题。
问:如果您没有调用jcmd <pid> GC.run会怎样?
答:在某个时候,JVM将决定旧代已经足够满,可以启动旧代收集。没有必要强制它。事实上,强制它通常是一个坏主意;参见Why is it bad practice to call System.gc()?
问:这是GC的一个缺陷吗?为什么当〉我〈认为内存是空闲的时候,GC不释放内存?
答:不,这不是缺陷。这是设计好的。
在早期回收内存的(假定的)好处与运行垃圾收集器的成本之间存在一个权衡,一般来说,当可收集的垃圾与不可收集的对象的比率很高时,GC算法最有效;即当堆接近(但不“太”接近)满时。
请注意,这些图并没有显示 reclaimable 空间。JVM能够有效地确定多少空间是可回收的唯一方法是实际运行GC来回收它。JVM不断地运行GC,只是为了在〉您〈认为应该释放内存时释放内存,这将是低效的(而且毫无意义)。
最后,即使您强制GC运行,* JVM也不愿意将内存还给OS* 以供其他进程使用。挂起内存比不断地缩小堆然后再重新扩大堆更有效。

rvpgvaaj

rvpgvaaj2#

这是很常见的,也是垃圾收集的缺点之一。你可以告诉垃圾收集者他应该开始清理你的记忆,但这并不意味着他会这样做。

System.gc();

Oracle官方文档指出:

调用gc方法建议Java虚拟机花费精力回收未使用的对象,以便使它们当前占用的内存可供快速重用

相关问题