java - 为什么(Oracle)JVM 有一个固定的内存使用上限(-Xmx)?

标签 java memory jvm

本着提问的精神Java: Why does MaxPermSize exist? ,我想问一下为什么Oracle JVM对其内存分配池的大小使用了一个固定的上限。

默认为物理 RAM 的 1/4(有上限和下限);因此,如果您有一个需要大量内存的应用程序,您必须手动更改限制(参数 -Xmx),否则您的应用程序将表现不佳,甚至可能因 OutOfMemoryError 而崩溃。

为什么这个固定的限制甚至存在?为什么 JVM 不像大多数操作系统上的本地程序那样按需分配内存?

这将解决 Java 软件的一整类常见问题(只需 Google 看看网上有多少关于通过设置 -Xmx 解决问题的提示)。

编辑:

一些答案​​指出,这将保护系统的其余部分免受内存泄漏失控的 Java 程序的影响;如果没有限制,这会耗尽所有内存而导致整个系统瘫痪。这是真实的。但是,对于任何其他程序也是如此,现代操作系统已经允许您限制程序的最大内存(Linux ulimit,Windows“作业对象”)。所以这并不能真正回答这个问题,即“为什么 JVM 的做法与大多数其他程序/运行时环境不同?”。

最佳答案

Why does this fixed limit even exist? Why does the JVM not allocate memory as needed, like native programs do on most operating systems?

原因是 GC 需要事先知道最大堆大小可以是多少。 JVM 显然能够将其堆...扩展到最大值...我敢肯定,移除该最大值将是一个相对小的变化。 (毕竟,其他 Java 实现会这样做。)同样有可能有一种简单的方式对 JVM 说“使用尽可能多的内存”。

我确信真正的原因是为了保护主机操作系统免受使用所有可用内存的错误 Java 应用程序的影响。使用无界堆运行是有潜在危险的。

基本上,如果某些应用程序试图使用所有可用内存,许多操作系统(例如 Windows、Linux)都会遭受严重的性能下降。例如,在 Linux 上,系统可能会严重抖动,导致系统上的所有内容都运行得非常缓慢。在最坏的情况下,系统将无法启动新进程,并且当操作系统拒绝其(合法的)更多内存请求时,现有进程可能会开始崩溃。通常,唯一的选择是重新启动。

如果默认情况下 JVM 以无限堆运行,那么任何时候有人运行 Java 程序时出现存储泄漏......或者只是试图使用过多的内存......他们就有可能导致整个操作系统崩溃。

总之,有一个默认的堆绑定(bind)是一件好事,因为:

  • 它可以保护您系统的健康,
  • 它鼓励开发人员/用户思考“饥饿”应用程序的内存使用情况,并且
  • 可能允许 GC 优化。 (正如其他答案所建议的那样:这是合理的,但我无法证实这一点。)

编辑

回应评论:

  • 并不重要为什么 Sun 的 JVM 存在于有界堆中,而其他应用程序则不然。他们这样做了,这样做的好处(IMO)很明显。也许一个更有趣的问题是,为什么其他托管语言默认设置它们的堆。

  • -Xmxulimit 方法在性质上是不同的。在前一种情况下,JVM 完全了解其运行的限制,并有机会相应地管理其内存使用情况。在后一种情况下,典型的 C 应用程序首先知道的是 malloc 调用失败时。典型的响应是退出并返回错误代码(如果程序检查 malloc 结果),或者因段错误而死。好的,理论上 C 应用程序可以跟踪它使用了多少内存,并尝试应对即将发生的内存危机。但这会很辛苦。

  • Java 和 C/C++ 应用程序的另一个不同之处在于前者往往更复杂且运行时间更长。实际上,这意味着 Java 应用程序更有可能遭受缓慢泄漏的困扰。在 C/C++ 案例中,内存管理更难的事实意味着开发人员不会尝试构建具有这种复杂性的单个应用程序。相反,他们更有可能通过让子进程的监听器进程派生来做事......然后退出来构建(比如说)复杂的服务。这自然会减轻子进程中内存泄漏的影响。

  • JVM“自适应”响应来自操作系统的请求以返还内存的想法很有趣。但是有一个大问题。为了归还一段内存,JVM首先必须清除该段中所有可访问的对象。通常这意味着运行垃圾收集器。但是如果系统处于内存危机中,运行垃圾收集器是你想要做的最后的事情......因为它几乎可以保证会产生大量的虚拟内存分页。

关于java - 为什么(Oracle)JVM 有一个固定的内存使用上限(-Xmx)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3358328/

相关文章:

java - 如何以编程方式模拟 Java FX 中的箭头键按下

java - emr如何在用户定义的函数中访问aws凭证

java - 当 Spring 发现两个同名的 bean 时,它会做什么?

java - 通过文法构建Java Decompiler会出现什么问题?

java - Spark中的并行bean类

Java DLL 链接错误

ios - MKMapView 释放内存

mysql - 将 MySQL innodb 数据库加载到内存中

c - 函数是否占用内存空间?

java - JVM 如何确保新对象内存分配的线程安全