导读java
JVM是Java Virtual Machine的缩写,中文名为Java虚拟机。它是一种用于计算设备的规范,是一个虚构出来的计算机,主要经过在实际的计算机上仿真模拟各类计算机功能来实现的。在实际运用过程当中,易观技术人员注意到一台开发机上各个微服务进程占用内存很高,随即使展开了调查......linux
现象:前段时间发现某台开发机上各个微服务进程占用内存很高,这里记录下解决思路,仅供参考。程序员
VIRT和RES都很高......spring
以其中某个进程为例(进程启动日期为8月9日,排查时候的时间是8月10日10:54:58,也就是说该进程运行时间应该不会超过48小时)sql
top命令查看该进程占用内存状况(能够看到此进程已经占用2.7G物理内存)springboot
为了排除掉是由于中途有压力测试的嫌疑,将此服务进行了重启,可是刚起的进程(19146),多线程
占内存状况RES:1.8G, VIRT:33.4G …架构
JVM进程动不动就是2G以上的内存,然而开发环境并没什么业务请求,谁是罪魁祸首 ?并发
解决问题以前,先复习下几个基础知识。
1. 什么是RES和VIRT?jvm
(1)进程当前使用的内存大小,但不包括swap out
(2)包含其余进程的共享
(3)若是申请100m的内存,实际使用10m,它只增加10m,与VIRT相反
(4)关于库占用内存的状况,它只统计加载的库文件所占内存大小
RES = CODE + DATA
(1)进程“须要的”虚拟内存大小,包括进程使用的库、代码、数据等
(2)假如进程申请100m的内存,但实际只使用了10m,那么它会增加100m,而不是实际的使用量
VIRT = SWAP + RES
2. Linux与进程内存模型
3. JVM内存模型(1.7与1.8之间的区别)
因此JVM进程内存大小大体为:
非heap(非heap=元空间+栈内存+…)+heap+JVM进程运行所需内存+其余数据
那么会是jvm内存泄漏引发的吗?
能够看到,堆内存一切正常(dump会引发FGC,但并不影响此结论)
那么多是SpringBoot的缘由吗?
为了验证此问题,经过部署系统在开发机上起了1个没有任何业务代码的springboot进程,仅仅是引入注册中心
查看此进程内存占用状况:
明显已经设置了Xmx为512MB,虽然Xmx不等于最终JVM所占总内存,但至少也不会误差太多; 那么使用jmap命令查看当前jvm堆内存配置和使用状况(下面的图2是在图1现场5分钟以后截取的)
因此从2次的jmap结果中,能够得出如下几个结论:
元空间(20.79MB)+ eden(834MB)+年老代(21MB)+线程栈(38*1024KB)+JVM进程自己运行内存+ NIO的DirectBuffer +JIT+JNI+…≈top(Res) 1.1G
当前jvm线程数统计:jstack 7311 |grep ‘tid’|wc –l (linux 64位系统中jvm线程默认栈大小为1MB)
Xmx设置为什么未生效?
查看部署系统的启动脚本,发现启动方式为:Java –jar $jar_file –Xms512m –Xmx1024m
正确的Java命令:
java [ options ] class [ arguments ]
java [ options ] -jar file.jar [ arguments ]
其实到这里,也找到了此问题缘由所在,Java –jar $jar_file –Xms512m –Xmx1024m被JVM解释成了程序的参数。
手动执行: java –Xms512m –Xmx1024m –jar ems-client-1.0.jar
至此,RES太高的问题已解决,可是VIRT的问题还在
使用系统命令pmap -x 3516查看进程的内存映射状况,会发现大量的64MB内存块存在;统计了下,大概有50多个65404+132=65536,正好是64MB,算起来大约3个多G
因而Google之,发现大体的缘由是从glibc2.11版本开始,linux为了解决多线程下内存分配竞争而引发的性能问题,加强了动态内存分配行为,使用了一种叫作arena的memory pool,在64位系统下面缺省配置是一个arena大小为64M,一个进程能够最多有cpu cores * 8个arena。假设机器是8核的,那么最多能够有8 * 8 = 64个arena,也就是会使用64 * 64 = 4096M内存。
然而咱们能够经过设置系统环境变量来改变arena的数量:
export MALLOC_ARENA_MAX=8(通常建议配置程序cpu核数)
配置环境变量使其生效,再重启该jvm进程,VIRT比以前少了快2个G:
总结:这里只是提供一种解决问题的思路,仅供参考;通常咱们遇到问题以后, 首先想到的是否是程序有问题,而后跟踪了好久仍是未找到问题根本缘由;几经周折, 才发现问题是出如今最容易被咱们忽视的地方(好比这里的脚本命令问题)!
欢迎工做一到五年的Java工程师朋友们加入Java程序员开发: 854393687
群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用本身每一分每一秒的时间来学习提高本身,不要再用"没有时间“来掩饰本身思想上的懒惰!趁年轻,使劲拼,给将来的本身一个交代!