首页 文章

为什么(Sun)JVM具有固定的内存使用上限(-Xmx)?

提问于
浏览
44

在问题Java: Why does MaxPermSize exist?的精神中,我想问一下为什么Sun JVM对其内存分配池的大小使用固定的上限 .

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

为什么这个固定限制甚至存在?为什么JVM不会根据需要分配内存,就像本机程序在大多数操作系统上一样?

这将解决Java软件的一大类常见问题(只需谷歌通过设置-Xmx来查看解决问题的网上有多少提示) .

编辑:

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

8 回答

  • -1

    将触发GC的上限和可分配的最大值分开是否更有意义?一旦分配的内存达到上限,GC就可以启动并释放一些内存到空闲池 . 有点像我清理我的办公桌,我与同事分享 . 我有一张大 table ,我在 table 上能容忍多少垃圾的门槛远低于我办公桌的大小 . 在垃圾收集之前,我不需要填满每一英寸 .

    我还可以将我使用的一些桌面空间返回给我的同事,他正在共享我的桌面......我明白jvms在将它们分配给自己之后不会将内存返回给系统,但它不一定不是那样吗?

  • 25

    我认为它的一部分与垃圾收集器(GC)的实现有关 . GC通常是惰性的,这意味着它只会在堆处于最大大小时才开始尝试在内部回收内存 . 如果没有设置上限,运行时将很快继续膨胀,直到它使用系统上的每个可用内存位 .

    这是因为从应用程序的角度来看,获取更多资源比使用已经拥有的资源充分利用更高效 . 这往往对Java的许多(如果不是大多数)使用有意义,Java是一种服务器设置,其中应用程序实际上是服务器上唯一重要的事情 . 当您尝试在Java中实现客户端时,它往往略微不太理想,它将同时在许多其他应用程序中运行 .

    请记住,对于本机程序,程序员通常会请求但也会明确地清理资源 . 对于进行自动内存管理的环境而言,这通常不正确 .

  • 3

    这是由于JVM的设计 . 其他JVM(如微软和某些IBM的JVM)可以根据需要使用系统中可用的所有内存,没有任意限制 .

    我相信它允许进行GC优化 .

  • -1

    为什么这个固定限制甚至存在?为什么JVM不会根据需要分配内存,就像本机程序在大多数操作系统上一样?

    原因是 NOT ,GC需要事先了解最大堆大小 . JVM显然能够将其堆扩展到最大......并且我确信删除该最大值将是一个相对较小的更改 . (毕竟,其他Java实现都是这样做的 . )同样可以有一种简单的方法来向JVM说"use as much memory as you like" .

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

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

    如果默认情况下JVM使用无界堆运行,那么每当有人运行带有存储泄漏的Java程序时......或者只是试图使用太多内存......它们可能会导致整个操作系统崩溃 .

    总之,拥有默认的堆绑定是一件好事,因为:

    • 它可以保护您系统的 Health ,

    • 它鼓励开发人员/用户通过"hungry"来考虑内存使用情况应用程序,和

    • 它可能允许GC优化 . (正如其他答案所暗示的那样:这是合情合理的,但我无法证实这一点 . )

    EDIT

    回应评论:

    • 为什么Sun 's JVMs live within a bounded heap, where other applications don' t并不重要 . 他们这样做,这样做的好处是(IMO)清楚 . 也许一个更有趣的问题是为什么其他托管语言默认情况下不会限制其堆 .

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

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

    • JVM响应"adaptively"响应来自操作系统的请求以回忆内存的想法很有意思 . 但是存在一个很大的问题 . 为了返回一段内存,JVM首先必须清除段中的任何可到达对象 . 通常这意味着运行垃圾收集器 . 但是,如果系统处于内存危机中,那么运行垃圾收集器是你想要做的最后一件事......因为它几乎可以保证产生一个虚拟内存分页 .

  • 1

    它根据需要分配内存,最多为-Xmx;)

    我能想到的一个原因是,一旦JVM为其堆分配了一定量的内存,它就永远不会放弃它 . 因此,如果您的堆没有上限,JVM可能只是获取系统上的所有可用内存,然后永远不会放弃它 .

    上限还告诉JVM什么时候需要进行完整的垃圾收集 . 如果您的应用程序仍处于上限,JVM将推迟垃圾回收并让应用程序的内存占用增长 .

    本机程序也可能由于内存不足错误而死亡,因为本机应用程序也有内存限制:系统上可用的内存 - 其他应用程序已经拥有的内存 .

    JVM还需要一个连续的系统内存块,以便有效地执行垃圾收集 .

    EDIT

    Contiguous memory claimhere

    JVM显然会让一些内存消失,但是默认配置是rare .

  • 6

    嗯,我会尝试总结到目前为止的答案 .

    JVM需要对其堆大小进行硬限制,这是没有技术原因的 . 它可以在没有一个的情况下实现,事实上许多其他动态语言都没有 .

    因此,为JVM提供堆大小限制只是实现者的设计决策 . 再猜测为什么这样做有点困难,可能没有一个原因 . 最可能的原因是它有助于保护系统免受Java程序的内存泄漏,否则可能耗尽所有RAM并导致其他应用程序崩溃或系统崩溃 .

    Sun可能已经省略了该功能,只是简单地告诉人们使用OS本机资源限制机制,但他们可能希望始终有限制,因此他们自己实现了 . 无论如何,JVM需要知道任何这样的限制(以适应其GC策略),因此使用OS本机机制不会节省太多编程工作 .

    此外,有一个原因可以解释为什么这样的内置限制对于JVM而言比对没有GC的“普通”程序(例如C / C程序)更重要:

    与具有手动内存管理的程序不同,使用GC的程序实际上并没有明确定义的内存要求,即使使用固定的输入数据也是如此 . 它只有最低要求,即在给定时间点实际存在(可达)的所有对象的大小总和 . 但是,在实践中,程序将需要额外的内存来保存死亡但尚未GCed的对象,因为GC无法立即收集每个对象,因为这会导致过多的GC开销 . 因此,GC只会不时地启动,因此堆上需要一些“喘息空间”,死对象可以等待GC .

    这意味着使用GC的程序所需的内存实际上是节省内存和良好吞吐量之间的折衷(通过让GC运行较少) . 因此,在某些情况下,将堆限制设置为低于JVM将尽可能使用的限制可能是有意义的,因此以牺牲性能为代价来节省RAM . 要做到这一点,需要有一种方法来设置堆限制 .

  • 2

    上面没有人给出的一个答案是JVM使用堆和非堆内存池 . 在堆上设置上限不仅定义了堆内存池可用的内存量,还定义了可用于NON-HEAP使用的内存量 . 我想JVM可以只在虚拟内存的顶部分配非堆,并在虚拟内存的底部堆积,并相互增长 .

    非堆内存包括构成JVM的DLL或SO以及正在使用的任何本机代码以及编译的Java代码,线程堆栈,本机对象,PermGen(有关已编译类的元数据)以及其他用途 . 我已经看到Java程序崩溃了,因为应用程序耗尽非堆内存的堆已经给了很多内存 . 这是我了解到,通过不将堆设置得太大来为非堆使用保留内存非常重要 .

    这在32位世界中产生了更大的差异,当然,应用程序通常只有2GB的虚拟地址空间,而不是64位的世界 .

  • 0

    我认为内存的上限与JVM是VM的事实有关 .

    由于任何物理机器都有一个给定(固定)的RAM,因此VM有一个 .

    最大大小使操作系统更容易管理JVM,并确保一些性能提升(交换更少) .

    Sun的JVM也适用于非常有限的硬件架构(嵌入式ARM系统),资源管理至关重要 .

相关问题