我正在深入了解内存分配在JVM中的工作原理。 我正在编写一个应用程序,其中我正在使用内存:堆空间异常。
据我所知,我可以将诸如Xms和Xmx之类的VM参数传递给JVM为正在运行的进程分配的堆空间。这是解决问题的一种可能方法,或者我可以检查代码是否存在内存泄漏并解决问题。
我的问题是:
1)JVM如何为自己实际分配内存?这与操作系统如何将可用内存传递给JVM有何关系?或者更一般地说,任何进程的内存分配实际上如何工作?
2)虚拟内存如何发挥作用?假设您有一个具有32GB物理内存的系统,并且您将所有32GB分配给您的Java进程。假设您的进程实际上消耗了所有32GB内存,我们如何强制使用虚拟内存而不是运行到OOM异常?
感谢。
答案 0 :(得分:23)
JVM如何为自己实际分配内存?
对于堆,它分配一个最大大小的大内存区域。最初这是虚拟内存,但随着时间的推移,它会成为操作系统控制下使用部分的真实内存
这与操作系统如何将可用内存传递给JVM有何关系?
JVM不知道操作系统中的空闲内存。
或者更一般地说,任何进程的内存分配实际上如何工作?
一般来说,它使用malloc和free。
虚拟内存如何发挥作用?
最初分配虚拟内存,并根据使用情况转换为实际内存。这对任何过程都是正常的。
假设您有一个具有32GB物理内存的系统,并且您将所有32GB分配给您的Java进程。
你做不到。操作系统需要一些内存,并有内存用于其他目的。即使在JVM中,堆也只是所用内存的一部分。如果你有32 GB的内存我建议最多24 GB。
假设你的进程实际上消耗了所有32GB的内存,
假设您有48 GB并且启动了一个使用32 GB主内存的进程。
我们如何强制使用虚拟内存而不是运行到OOM异常?
应用程序从一开始就使用虚拟内存。您不能使堆太大,因为如果它开始交换您的机器(不仅仅是您的应用程序)将变得无法使用。
通过使用off heap memory,您可以使用比物理更多的内存。但是,托管内存必须位于物理内存中,因此如果需要32 GB堆,请购买64 GB主内存。
答案 1 :(得分:7)
想要分配内存的JVM(或任何进程)将调用C运行时“malloc”函数。此函数维护C运行时的堆内存。反过来,它从操作系统内核获取内存 - 用于此的函数取决于平台;在Linux中,它可以使用brk or sbrk系统调用。
一旦JVM获得了内存,它就会管理内存本身,将其中的一部分分配给正在运行的程序创建的各种对象。
虚拟内存完全由操作系统内核处理。内核管理物理内存页面到各种进程的地址空间的映射;如果物理内存少于系统中所有进程所需的内存,则OS内核会将其中的一些内容交换到磁盘。
您不能(也不需要)强制进程使用虚拟内存。它对您的流程是透明的。
如果您遇到“内存不足”错误,原因很可能是:
正在超出JVM限制。这些由您在问题中声明的各种命令行参数和/或属性控制
操作系统可能已用尽交换空间(或者没有配置任何交换空间以开始)。或者某些操作系统甚至不支持虚拟内存,在这种情况下你的实际内存不足。
大多数操作系统都有管理员限制进程占用内存量的工具 - 例如,在Linux中setrlimit系统调用和/或ulimit shell命令,这两者都设置了限制内核会观察到的。如果进程请求的内存多于限制允许的内存,则尝试将失败(通常会导致内存不足消息)。
答案 2 :(得分:2)
JVM从操作系统分配Java堆内存,然后管理 Java应用程序的堆。当应用程序创建新的时 对象,JVM子堆分配一个连续的堆内存区域 存储它。堆中的对象,由任何其他对象引用 是“活着的”,只要它继续存在就会留在堆里 引用。不再引用的对象是垃圾和罐头 从堆中清除以收回它们占用的空间。 JVM 执行垃圾收集(GC)以删除这些对象, 重新组织堆中剩余的对象 资料来源:http://pubs.vmware.com/vfabric52/index.jsp?topic=/com.vmware.vfabric.em4j.1.2/em4j/conf-heap-management.html
在使用虚拟内存的系统中,物理内存分为 同样大小的页面。进程所处理的内存也是分开的 到相同大小的逻辑页面。当一个进程引用一个 内存地址,内存管理器从磁盘中获取该页面 包括引用的地址,并将其放置在空的物理中 RAM中的页面。
来源:http://searchstorage.techtarget.com/definition/virtual-memory
答案 3 :(得分:2)
此博客介绍了您可能会觉得有用的Java内存利用率:
http://www.waratek.com/blog/november-2013/introduction-to-real-world-jvm-memory-utilisation