JVM运行时占用的内存

2020-03-04  本文已影响0人  taj3991

一个线上服务内存占用带来的问题

在Oracle官网给出的JVM调优文档中关于堆的调整技巧有以下三个方面:

第三点将初始堆大小设置和最大堆大小相同,可以减少JVM重新分配内存,伸缩J堆大小时候的GC压力,在线上实际运行的时候给-Xms和-Xmx参数均设置成2048m,可是使用htop命令查看进程消耗的内存时候,发现只使用了1098m。Xms是设置初始堆和最小堆的大小,难道出问题了么?使用jmap命令输出堆的实际情况,如下:

[root@pc ~]# jmap -heap 15189
Attaching to process ID 15189, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.202-b08

using thread-local object allocation.
Parallel GC with 2 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 2147483648 (2048.0MB)
   NewSize                  = 715653120 (682.5MB)
   MaxNewSize               = 715653120 (682.5MB)
   OldSize                  = 1431830528 (1365.5MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 677380096 (646.0MB)
   used     = 359083872 (342.4490661621094MB)
   free     = 318296224 (303.5509338378906MB)
   53.01069135636368% used
From Space:
   capacity = 18874368 (18.0MB)
   used     = 8472112 (8.079635620117188MB)
   free     = 10402256 (9.920364379882812MB)
   44.886864556206596% used
To Space:
   capacity = 18350080 (17.5MB)
   used     = 0 (0.0MB)
   free     = 18350080 (17.5MB)
   0.0% used
PS Old Generation
   capacity = 1431830528 (1365.5MB)
   used     = 45051784 (42.96472930908203MB)
   free     = 1386778744 (1322.535270690918MB)
   3.14644667221399% used

31785 interned Strings occupying 3781800 bytes.

查看以上信息发现,堆分配大小没有问题的呀!这是为什么呢。。查了一会资料,JVM启动的时候,将虚拟地址与本机物理内存地址进行映射,实际运行的时候并没有使用到2048m内存,在堆内存不够用的时候回向操作系统申请物理内存,而操作系统htop命令查看的内存是RES即实际占用的物理内存,刚启动的时候比实际Xms来的小。

这里会带来两个问题:

我们可以给JVM添加-XX:+AlwaysPreTouch这个参数优化这个问题,不过这个参数在JDK8下有一个副作用会大大提高启动时间

在没有配置-XX:+AlwaysPreTouch参数即默认情况下,JVM参数-Xms申明的堆只是在虚拟内存中分配,而不是在物理内存中分配:它被以一种内部数据结构的形式记录,从而避免被其他进程使用这些内存。这些内存页直到被访问时,才会在物理内存中分配。当JVM需要内存的时候,操作系统将根据需要分配内存页。

配置-XX:+AlwaysPreTouch参数后,JVM将-Xms指定的堆内存中每个字节都写入’0’,这样的话,除了在虚拟内存中以内部数据结构保留之外,还会在物理内存中分配。并且由于touch这个行为是单线程的,因此它将会让JVM进程启动变慢。所以,要么选择减少接下来对每个缓存页的第一次访问时间,要么选择减少JVM进程启动时间

不过在JDK9中可以使用并行操作,Parallelize Memory Pretouch。

这里又有疑问了,当JVM内存申请使用完毕后会返还给物理内存吗?

设置了Xmx参数,JVM一定不会超过这个大小么?超过一定会OOM或者SOF吗?

JVM内存占用情况

JVM进程主要占用内存的一些地方,其中JDK8之前JMM模型中共享的永久区取消变为元空间(metaspace)依旧存放于堆外内存之中。

由以上可以看出,JVM实际占用的内存实际上包含堆内和堆外的,而虚拟机启动参数Xms和Xmx限制的是堆的大小,实际虚拟机内存可能大得多。

总结

JVM在默认情况下启动的时候,

上一篇 下一篇

猜你喜欢

热点阅读