gc1不释放操作系统内存

juud5qan  于 2021-06-29  发布在  Java
关注(0)|答案(1)|浏览(401)

我用默认的垃圾收集器(g1gc)运行一个java应用程序。我不知道g1cc什么时候释放内存。在 htop 我看到了 700M 应用程序使用的位置。在我做了之后 jcmd <pid> GC.run 下降到大约 250M . 这是不是意味着gc不会自己做这些?

ijxebb2r

ijxebb2r1#

总结
在jdk 11之前,堆收缩(将内存返回操作系统)只在完全收集之后触发,因为更改的重要性足以保证该操作不会影响性能。
使用jdk12+(检查到15),堆收缩也会在正常的收集周期中触发,这使得通常不涉及完整收集的应用程序更有可能看到堆收缩。
细节
g1 gc仅在空间耗尽的情况下执行完全收集,除非手动触发(如您所做的那样):
[…]如果应用程序在收集活动性信息时内存不足,g1会像其他收集器一样执行就地停止世界完全堆压缩(full gc)[…]
收集周期由仅年轻阶段和空间回收阶段组成。
如果最初分配新对象的关联eden空间耗尽,则会发生“仅年轻”阶段。可触及的物体被疏散(移动)到幸存者空间。如果幸存者空间耗尽,可到达的对象将被疏散到另一个幸存者空间或旧一代(如果对象可到达或“存活”给定数量的集合)。
空间回收取决于旧代的大小,由初始堆占用百分比(ihop)控制。默认值( -XX:InitiatingHeapOccupancyPercent )是45%,但ihop由gc调整以优化收集间隔(称为“自适应ihop”)。这个阶段也处理年轻一代,因此它被称为“混合集合”。
g1 gc旨在
[…]在延迟和吞吐量之间提供最佳平衡[…]
g1尝试将垃圾收集延迟尽可能长的时间,并尝试避免完全的垃圾收集。
有关详细信息,请参阅https://docs.oracle.com/javase/9/gctuning/garbage-first-garbage-collector.htm#jsgct-guid-1cdeb6b6-9463-4998-815d-05e095bfbd0f
gc试图避免堆空间的释放(将内存还给操作系统),因为如果在以后某个时间点需要这些空间,那么这可能会导致性能下降。
根据jdk9中的g1源代码,收缩只在完全收集(显式收集或不显式收集)之后进行,并且只在满足特定阈值的情况下进行。 G1CollectedHeap::do_full_collection 电话 G1CollectedHeap::resize_if_necessary_after_full_collection ,它处理收缩过程并生成以下gc日志输出:

log_debug(gc, ergo, heap)(
  "Shrink the heap. requested shrinking amount: "
  SIZE_FORMAT "B aligned shrinking amount: "
  SIZE_FORMAT "B attempted shrinking amount: "
  SIZE_FORMAT "B",
  shrink_bytes, aligned_shrink_bytes, shrunk_bytes);

根据jdk15中的g1源代码,shinking是针对完整集合以及并发的mark和sweep集合进行的。 G1FullCollector::complete_collection 电话 G1CollectedHeap::prepare_heap_for_mutators 反过来又叫 G1CollectedHeap::resize_heap_if_necessary . 实际的收缩过程和日志消息与jdk9相同。与jdk9相比,jdk12及更高版本在所谓的重新标记阶段也执行收缩( G1ConcurrentMark::remark 电话 G1CollectedHeap::resize_heap_if_necessary ),在正常收集周期的上下文中。
这一变化是由以下因素引起的:
http://hg.openjdk.java.net/jdk/jdk/rev/08041b0d7c08
一种简单的监控方法是 -verbose:gc . 使用 -Xlog:gc=debug 在收缩的情况下查看上面提到的日志输出。

相关问题