JVM内存分配理解

JVM进程内存疑惑

一段时间,老是收到服务器内存不够用的告警(运维设置的可用内存低于90%即告警),登录服务器查看,发现应用服务运行依然正常,只是机器物理内存使用确实超过了90%,因此专门花时间了解一下。

服务器内存计划分配情况:

总内存:8G,部署了2个java应用A和B:一个2G和另一个2~3G。使用的是HotSpot虚拟机1.7版本,详细启动参数如下:

A: -Xms2G -Xmx3G -XX:PermSize=128m -XX:MaxPermSize=512m,该应用的特点是:TCP路由服务器,NIO长连接创建销毁比较频繁,同时在线的连接数在200左右

B: -Xms2G -Xmx2G -XX:PermSize=128m -XX:MaxPermSize=512m,该应用特点是:业务逻辑后台处理服务器,实时性不高,没有什么长连接。

告警时,机器物理内存只剩下100多M,B应用占了2.3G,A应用占了4.8G。

A应用的PID是4995,B应用的PID是12335

最大的疑惑就是A应用怎么占用了这么多(4.3G,堆最大也只有3G)?多出的1.8G内存到哪去了?

JVM虚拟机规范及HotSpot实现理解


引入一张网络图片

方法区、JAVA堆、虚拟机栈和本地方法区等,是JVM虚拟机的规范,我们用HotSpot虚拟机参数大概的映射一下:

-Xms3G -Xmx3G -Xmn1G: 会影响JAVA堆区的内存大小,即HotSpot里新生代和年老代

--XX:PermSize=256m -XX:MaxPermSize=512m:会影响方法区的内存大小,即HotSpot里永生代

-Xss256k: 会影响虚拟机栈的内存大小,它设置的是单个线程栈的大小


JVM进程内存分配理解实战


JVM进程内存 ≈ JVM程序自身占用内存+Java永久代 + Java堆(新生代和老年代) + 线程栈+ Java NIO(直接内存)

1. 在linux环境中可以通过ps -xH|grep {pid}|wc -l来统计该应用的线程数,线程数*Xss=线程栈总内存

2. JVM程序自身占用内存,这个可以大概估一下,理论上应该占用不多

3. 可以通过jmap -heap {pid}来查看新生代、老年代和永久代的内存情况

4. NIO直接内存可以通过netstat -np|grep {pid}|wc -l统计出当前nio数,再乘以每个nio所分配ByteBuffer大小(读写缓冲区)

Jvm内存回收疑惑

堆内存回收和直接内存回收机制, JVM版本和参数影响:

-XX:+DisableExplicitGC

-XX:MaxDirectMemorySize=256M

场景:jvm进程随着运行时间在不断的消耗内存,但堆内存并没有报oom, 到一定程度,该进程被OS当做bad program 给kill掉了......

你可能感兴趣的:(JVM内存分配理解)