了解JVM内存分配和Java内存不足:堆空间

了解JVM内存分配和Java内存不足:堆空间,java,memory,memory-management,jvm,out-of-memory,Java,Memory,Memory Management,Jvm,Out Of Memory,我正在研究如何真正理解JVM中的内存分配工作。 我正在编写一个内存不足的应用程序:堆空间异常 我知道我可以传入VM参数,比如Xms和Xmx,以增加JVM为正在运行的进程分配的堆空间。这是问题的一种可能解决方案,或者我可以检查我的代码是否存在内存泄漏,并在那里修复问题 我的问题是: 1) JVM实际上是如何为自己分配内存的?这与操作系统如何向JVM传递可用内存有关?或者更一般地说,任何进程的内存分配实际上是如何工作的 2) 虚拟内存是如何发挥作用的?假设您有一个具有32GB物理内存的系统,并将所有

我正在研究如何真正理解JVM中的内存分配工作。 我正在编写一个内存不足的应用程序:堆空间异常

我知道我可以传入VM参数,比如Xms和Xmx,以增加JVM为正在运行的进程分配的堆空间。这是问题的一种可能解决方案,或者我可以检查我的代码是否存在内存泄漏,并在那里修复问题

我的问题是:

1) JVM实际上是如何为自己分配内存的?这与操作系统如何向JVM传递可用内存有关?或者更一般地说,任何进程的内存分配实际上是如何工作的

2) 虚拟内存是如何发挥作用的?假设您有一个具有32GB物理内存的系统,并将所有32GB分配给Java进程。假设您的进程实际上消耗了所有32GB的内存,我们如何强制该进程使用虚拟内存,而不是运行OOM异常

谢谢

  • JVM从操作系统分配Java堆内存,然后管理 Java应用程序的堆。当应用程序创建新的 对象,JVM子对象将连续的堆内存区域分配给 保存它。堆中被任何其他对象引用的对象 是“活的”,并且只要它继续存在,就一直在堆中 参考。不再被引用的对象是垃圾,可以 从堆中清除以回收它们占用的空间。JVM 执行垃圾收集(GC)以删除这些对象, 重新组织堆中剩余的对象。
    资料来源:

  • 在使用虚拟内存的系统中,物理内存分为 大小相同的页面。进程寻址的内存也被划分 放入相同大小的逻辑页。当进程引用 内存地址,内存管理器从磁盘获取 包括引用的地址,并将其放置在空的物理地址中 在内存中翻页

  • 来源:

    想要分配内存的JVM(或任何进程)将调用C运行时“”函数。此函数用于维护C运行时的堆内存。它反过来从操作系统内核获取内存——用于此操作的函数依赖于平台;在Linux中,它可能使用系统调用

    一旦JVM获得了内存,它就会管理内存本身,将部分内存分配给运行程序创建的各种对象

    虚拟内存完全由操作系统内核处理。内核管理物理内存页到各个进程地址空间的映射;如果系统中的物理内存少于所有进程所需的内存,那么操作系统内核将把其中的一部分交换到磁盘上

    您不能(也不需要)强制进程使用虚拟内存。它对您的流程是透明的

    如果出现“内存不足”错误,则原因可能是:

  • 正在超出JVM限制。如您在问题中所述,它们由各种命令行参数和/或属性控制

  • 操作系统可能已用完交换空间(或者没有配置任何交换空间以启动)。或者有些操作系统甚至不支持虚拟内存,在这种情况下,您的实际内存已经用完了

  • 大多数操作系统都为管理员提供了限制进程占用内存量的工具,例如,在Linux中,系统调用和/或ulimit shell命令都设置了内核将遵守的限制。如果进程请求的内存超过限制允许的内存,则尝试将失败(通常会导致内存不足消息)

  • JVM实际上是如何为自己分配内存的

    对于堆,它分配一个最大大小的大型连续内存区域。然而,最初这是虚拟内存,随着时间的推移,它会在操作系统的控制下成为所使用部分的真实内存

    这与操作系统如何向JVM传递可用内存有关

    JVM不知道操作系统中的可用内存

    或者更一般地说,任何进程的内存分配实际上是如何工作的

    一般来说,它使用malloc和free

    虚拟内存是如何发挥作用的

    最初分配虚拟内存,并在使用时将其转换为实际内存。这对于任何过程来说都是正常的

    假设您有一个具有32GB物理内存的系统,并将所有32GB分配给Java进程

    你不能。操作系统需要一些内存,并且会有其他用途的内存。即使在JVM中,堆也只是所用内存的一部分。如果你有32 GB的内存,我建议最大堆容量为24 GB

    假设您的进程实际上消耗了所有32GB的内存

    假设您有48 GB,并且启动了一个使用32 GB主内存的进程

    我们如何强制流程使用虚拟内存,而不是遇到OOM异常

    应用程序从一开始就使用虚拟内存。您不能使堆太大,因为如果它开始交换您的计算机(不仅仅是您的应用程序)将变得不可用


    通过小心地使用堆外内存,可以使用比物理内存更多的内存。但是,托管内存必须位于物理内存中,因此如果您需要32 GB的堆,请购买64 GB的主内存。

    本博客介绍Java内存利用率,您可能会发现这一点很有用:


    如果您还没有使用过像VisualVM这样的分析器,请使用它。它可以让您深入了解应用程序内部发生的情况,例如哪些对象没有被垃圾收集,以及何时分配内存。问题:您能告诉我,为什么JVM_outOfMemory是一个错误而不是例外。@TusharPandey来自Javadoc 8 for error