【问题标题】:GC signal from kernel instead of fixed JVM heap size来自内核的 GC 信号,而不是固定的 JVM 堆大小
【发布时间】:2015-02-16 10:54:59
【问题描述】:

固定的堆大小永远不会是最佳的。您要么将其设置得太低并耗尽内存,要么将其设置得太高并浪费内存。并行运行的 JVM 进程越多,这个问题就越严重。即使对于一个 JVM,也不可能使用一台机器中的所有 RAM。越接近最大值,被OOM杀手杀死的风险就越大。

我理解固定堆大小的原因:垃圾回收。在不知道还有多少可用内存的情况下,JVM 将不知道何时执行 GC。

一个想法是将这个决定从 JVM 传递给内核。内核可以做出最优的全局决策,而不是次优的局部决策。我想这可以通过引入一个告诉 JVM 执行 GC 的新信号来工作。每当需要回收一些内存时,内核就会发送此信号。

这样的事情存在吗?我误解了这个问题吗?这是个坏主意吗?

【问题讨论】:

  • 你误解了这个问题。至少对于 Oracle/OpenJDK,内核不参与 GC。堆是在 JVM 启动时预先分配的,直到程序退出时内核才会触及。
  • 堆没有预先分配。仅保留虚拟地址空间,但并未实际分配。

标签: java linux garbage-collection jvm


【解决方案1】:

最大堆大小的主要原因是允许管理员控制失控/泄漏的程序;它与垃圾收集完全无关。您可以使用ulimit 等操作系统工具执行相同操作,但这些工具不与 Java 集成,因此如果超出限制,Java 代码将无法再响应(因为大多数操作系统会在达到限制时强行终止进程)。因此,Java 的发明者需要一种不同的方法来做到这一点:他们允许您在命令行上指定最大堆大小,并为您提供 OutOfMemoryException,您可以在不终止的情况下捕获和处理它。

请记住,在 1994 年发布 Java 时,1GB 的内存仍然很多。此外,大多数 Java VM 运行在通常 256MB RAM 的手机和嵌入式设备上。

GC 本身通常由你有多少空闲堆触发,无论堆是否有上限。 Java 总是在向操作系统请求更多内存之前尝试重新获得内存 - GC 可能很昂贵,而更多内存意味着更昂贵。因此,将当前对象的数量保持在最低限度是一种自然的优化。很多人之所以认为max.堆大小将触发 GC 是这样的:当 Java 由于堆限制而无法从 OS 分配更多内存时,GC 将非常频繁地运行。那是大多数人意识到 GC 完全运行的时候。所以当这两个东西没有真正联系时,很容易混淆。

【讨论】:

    【解决方案2】:

    固定的堆大小永远不会是最佳的。

    堆大小本身永远不会固定。它根据应用程序的需要增长和缩小。从 Java 5 开始,如果集合不使用 X% 的空间,则可以将内存返回给操作系统。它使用XX:MaxHeapFreeRatio 属性进行调整。

    内核会在需要时发送此信号 回收一些内存。

    例如,内核如何知道 java 是否占用了内存,或者它是否可以从 java 中回收一些内存?应用程序真的需要 4GB 的内存还是存在占用更多内存并导致 OOM 的线程泄漏?内核永远不会知道这一点。

    这样的事情存在吗?

    XX:MaxHeapFreeRatio 属性是我所知道的最接近将内存还给操作系统的属性。

    我链接到的文档中有更多关于为这些属性设置正确值的建议。

    除非您遇到暂停问题,否则请尝试授予尽可能多的内存 可以到虚拟机。默认大小(64MB)通常太 小。

    将 -Xms 和 -Xmx 设置为相同的值可提高可预测性 从虚拟机中删除最重要的大小决定。 另一方面,如果你做一个虚拟机不能补偿 糟糕的选择。

    当你增加内存的数量时,一定要增加内存 处理器,因为分配可以并行化。

    【讨论】:

    • 谢谢! JVM如何知道内存是否可以回收?它没有,它只是运行一个 GC 并查看会发生什么。内核也会这样做:发送信号,看看会发生什么。并且没有任何程序可以知道这 4GB 是出于正当原因使用还是泄漏。我错过了什么吗?
    • 正如Deepak所说:如果空闲堆内存量超过MaxHeapFreeRatio,Java会将这块内存返回给OS。
    猜你喜欢
    • 2011-07-18
    • 2010-12-11
    • 2011-04-25
    • 2022-11-23
    • 2013-06-30
    • 2015-09-04
    • 1970-01-01
    • 2010-10-01
    • 1970-01-01
    相关资源
    最近更新 更多