已用内存、已提交内存和最大堆内存的差异

我正在监视 OutOfMemoryException 的 spark 执行器 JVM。我使用Jconsole连接到执行器JVM。以下是Jconsole的快照:enter image description here

在图像中,使用的内存显示为3.8G,提交的内存为8.6G,最大内存也是8.6G,任何人都可以解释已用内存和已提交内存之间的区别或任何解释它的链接。


答案 1

MemoryUsage 的 Java Doc,

getUsed 是:

已用内存量(以字节为单位)

getCommitted()

返回提交供 Java 虚拟机使用的内存量(以字节为单位)。此内存量保证供 Java 虚拟机使用。

getMax()

返回可用于内存管理的最大内存量(以字节为单位)。如果未定义最大内存大小,则此方法返回 -1。

如果此内存量大于已提交的内存量,则不能保证此内存量可用于内存管理。即使已用内存量未超过此最大大小,Java 虚拟机也可能无法分配内存。


答案 2

首先,它们的所有测量单位都是字节used < committed < max

  • init:JVM 在启动时从操作系统请求的初始内存量。
    • 这由java命令的cli选项控制。请参见 2-Xms
  • used:实际正在使用的内存量,即所有对象消耗的内存,包括无法访问但尚未被垃圾回收的对象。
    • 它可以低于初始化
  • 已提交:目前在操作系统级别为 JVM 进程保留的内存量。
    • 它可以等于或大于所使用的内存,JVM可以从操作系统请求/分配更多的内存,而不是真正使用它,但操作系统无论如何都会为java进程保留该内存。
    • 它可能会下降,甚至可能低于init,因为JVM可以将内存释放回操作系统。
    • 如果JVM需要更多的内存,将尝试从操作系统分配更多内存,然后提交的内容将上升,但即使请求的内存量低于最大值,操作系统也总是有可能运行内存。
    • 如果您正在尝试创建新对象,那么JVM不需要从操作系统请求更多内存,因此可以保证它会成功。used < committed
    • 如果您正在尝试创建新对象并且内存总量将超过,那么JVM需要在创建对象之前从操作系统分配更多内存,这不能保证成功(操作系统也可能耗尽内存)committed
  • max:JVM 尝试从操作系统请求/分配的最大内存量
    • 由 cli 选项控制。请参见 2-Xmx
    • 不能保证JVM能够分配这么多,操作系统可能会因为其他进程保留它而耗尽内存。

所以在OP的例子中

  • 使用量为3.8G
  • 承诺最大值为 8.6G

这意味着JVM可以在堆中分配高达8.6G的对象,这是有保证的,它不必要求操作系统这样做,因为它已经分配了。如果JVM在某些时候需要比这更多的内存,因为它需要分配更多的对象,并且它不能通过垃圾回收释放任何内存,那么它将在OOM中失败,因为8.6G已经是它允许请求的最大值(我猜因为它是从.-Xmx8600M