如何确定要为java堆分配多少物理内存?

时间:2019-05-28 04:01:47

标签: java memory garbage-collection jvm heap-memory

我有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                                     

在运行pmap命令时,我看到只有〜3.9g 堆作为 RES 存在,其余 5.7g位于虚拟< / strong>。

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的最小堆(-Xms),那么最初为什么只分配3.9g RES。这与保持-Xms低不一样吗?那么,保持-Xms = -Xmx的意义是什么?
  3. 在什么基础上决定RES中应该有多少堆?阅读某处由操作系统管理的地方,但有任何粗略的逻辑吗?
  4. 有什么方法可以确保分配的堆已被实际使用?

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:-1)

  1. Yes HEAP始终是RES
  2. This answer建议dd.mm.yyyy hh24:mi:ss是GC的提示,在什么时候需要进行完整的垃圾回收。使用本地JVM进行测试,我可以确认它不会立即保留内存。您得到的是,您的JVM不会阻塞大量未使用的内存,但是随着GC的运行减少,JVM将更快地达到下界。
  3. 由1解答:RES始终包含所有HEAP
  4. 我的理解是,您的选择将实现您的预​​期目标。您的应用程序将获取9GB的内存,然后更频繁地开始垃圾回收。有other options之类的-Xms,如果您需要更多优化,则取决于gargbage collector used的选项。

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