java堆分配多少物理内存是如何决定的?

How is it decided that how much physical memory is to be allocated to java heap?

我有一台 16G RAM 的机器。我 运行 一个带有参数 -Xms9G -Xmx9G 的 java 应用程序。 当我使用 运行 top 命令时,我看到我的 java 进程占用 13.8g VIRT,但只有 4.6g RES

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 5019 root      20   0 13.8g 4.7g  18m S  0.7 30.7   3:28.39 java                                     

在 运行ning pmap 命令上,我看到只有 ~3.9g 的堆作为 RES, 其余 5.7g 在虚拟中.

Address           Kbytes     RSS   Dirty Mode   Mapping
0000000580000000 9452384 4074228 4074228 rw---    [ anon ]

在使用 jvmtop 监控 HPCUR 时,我观察到当 HPCUR 达到大约 3g 时触发了 GC。

PID MAIN-CLASS        HPCUR HPMAX NHCUR NHMAX    CPU     GC    VM USERNAME   #T DL
 5019 .1-SNAPSHOT.jar  408m 9216m  192m   n/a  0.25%  0.00% O8U20   webapp  823

我观察到进程的 RES 逐渐增加,RES 中的堆内存(通过 pmap)也逐渐增加。结果 GC 阈值增加。

我对此行为有几个问题。

  1. 是否只使用了 RES 中存在的堆,而不使用 VIRT?
  2. 如果我分配了 9G min heap (-Xms),那么最初为什么只分配了 3.9g RES。这与保持低 -Xms 不一样吗?那么保留 -Xms=-Xmx 有什么意义呢?
  3. RES中堆的大小是根据什么决定的?在某处读到它由 OS 管理,但有什么粗略的逻辑吗?
  4. 有什么方法可以确保实际使用分配的堆?
  1. Yes HEAP 是 RES(只要它适合主内存)
  2. 表明 -Xms 是对 GC 的提示,在什么时候需要进行完整的垃圾收集。使用我的本地 JVM 进行测试,我可以确认它不会立即保留内存。您获得的是您的 JVM 不会阻塞大量未使用的内存,但会更快地到达您的下限,因为 GC 运行s 较少。
  3. 1 的回答:RES 总是包含所有的 HEAP
  4. 我的理解是您的选择将实现您的意图。您的应用程序将占用 9GB 内存,然后更频繁地启动垃圾收集。如果需要更多优化,还有other options like MinHeapFreeRatio and options that depend on the gargbage collector used

您是否打印了 GC 日志并确认有问题?如果您在达到 9G 之前在应用程序启动时看到很多 GC 运行,我会进一步查看。如果在达到 9G 之前几乎没有任何 GC 运行 我会说一切都很好。

  • VIRT 表示虚拟内存 - 这是进程的整个保留地址 space。 RSS 是驻留集大小 - 分配在物理 RAM 中的虚拟地址部分 space。对于任何地址范围(不仅是堆),RSSVIRT 的子集,可能是完整的或空的。好像您已经探索过 pmap - 对于每个虚拟地址范围,它显示了物理分配内存 (RSS) 的确切数量。
  • OS 在第一次访问时延迟分配物理页面。这就是为什么在相应的页面被读取或写入之前,即使已提交的内存也不是 RSS 的一部分。堆的大部分不在 RSS 中这一事实意味着堆的这一部分从未被触及过。另见 .
  • 有一个 JVM 选项 -XX:+AlwaysPreTouch 强制接触堆的每一页,从而使其成为 RSS 的一部分。试试 java -Xms9G -Xmx9G -XX:+AlwaysPreTouch.