springboot内存占用过高问题排查 - jvm内存使用分析
排查springboot内存占用过高问题
所需命令:
ps命令:Linux命令。强大的进程状态监控命令。可以查看进程以及进程中线程的当前CPU使用情况。属于当前状态的采样数据。
top命令:Linux命令。可以查看实时的CPU使用情况。也可以查看最近一段时间的CPU使用情况。
这两个命令详情可参考:https://blog.csdn.net/XiXavier/article/details/108566416
jps命令 :(Java Virtual Machine Process Status Tool)是JDK 1.5提供的一个显示当前所有java进程pid的命令。jps存放在JAVA_HOME/bin/jps,使用时为了方便请将JAVA_HOME/bin/加入到Path.会用 ps 命令也行。
常用的参数:
-q:只显示pid,不显示class名称,jar文件名和传递给main 方法的参数
-m:输出传递给main 方法的参数,在嵌入式jvm上可能是null
-l:输出应用程序main class的完整package名 或者 应用程序的jar文件完整路径名
-v: 输出传递给JVM的参数示例:
[root@new-frame-251 texu]# jps -lv |grep 32528
32528 hoau-texu-service-0.0.1-SNAPSHOT-exec.jar -Xms80m -Xmx80m -XX:SurvivorRatio=8 -XX:+UseConcMarkSweepGC -XX:+HeapDumpOnOutOfMemoryError
[root@new-frame-251 texu]#
jstack命令:Java提供的命令。可以查看某个进程的当前线程栈运行情况。根据这个命令的输出可以定位某个进程的所有线程的当前运行状态、运行代码,以及是否死锁等等。
[root@new-frame-251 texu]# jstack
Usage:jstack [-l] <pid>(to connect to running process)jstack -F [-m] [-l] <pid>(to connect to a hung process)jstack [-m] [-l] <executable> <core>(to connect to a core file)jstack [-m] [-l] [server_id@]<remote server IP or hostname>(to connect to a remote debug server)Options:-F to force a thread dump. Use when jstack <pid> does not respond (process is hung)-m to print both java and native frames (mixed mode)-l long listing. Prints additional information about locks-h or -help to print this help message
[root@new-frame-251 texu]#统计进程中线程个数:(linux 64位系统中jvm线程默认栈大小为1MB)
[root@new-frame-251 texu]# jstack 32528 |grep tid|wc -l
251
[root@new-frame-251 texu]#
查看进程中线程情况:
GC task thread :垃圾回收线程
http-nio thread :tomcat网络处理网络请求线程
C2CompilerThread :JIT编译线程,动态编译Java运行代码,C2表示编译的是server端代码
DubboServerHandler-10.39.251.159:20914-thread-200 : dubbo线程
还有很多其他的线程。。。
:
jmap命令: Java提供的命令。查看jvm内存使用情况。
jmap -heap [pid] : 查看整个JVM内存状态,要注意的是在使用CMS GC 情况下,jmap -heap的执行有可能会导致JAVA 进程挂起
jmap -histo [pid] : 查看JVM堆中对象详细占用情况
jmap -histo:live pid : 指定了live子选项,则只计算活动的对象
jmap -dump:format=b,file=文件名 [pid] : 导出整个JVM 中内存信息
......
jvisualvm.exe : java 自带的jvm监控工具,java的安装目录 bin/ 中
pmap命令: - report memory map of a process(查看进程的内存映像信息)pmap命令用于报告进程的内存映射关系
用法pmap [ -x | -d ] [-q] pids...pmap -V
选项含义-x extended Show the extended format. 显示扩展格式-d device Show the device format. 显示设备格式-q quiet Do not display some header/footer lines. 不显示头尾行-V show version Displays version of program. 显示版本
扩展格式和设备格式域:Address: start address of map 映像起始地址Kbytes: size of map in kilobytes 映像大小RSS: resident set size in kilobytes 驻留集大小Dirty: dirty pages (both shared and private) in kilobytes 脏页大小Mode: permissions on map 映像权限: r=read, w=write, x=execute, s=shared, p=private (copy on write) Mapping: file backing the map , or '[ anon ]' for allocated memory, or '[ stack ]' for the program stack. 映像支持文件,[anon]为已分配内存 [stack]为程序堆栈Offset: offset into the file 文件偏移Device: device name (major:minor) 设备名
jvm各项参数说明
-XX:MetaspaceSize=128m (元空间默认大小)
-XX:MaxMetaspaceSize=128m (元空间最大大小)
-Xms1024m (堆默认大小)此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
-Xmx1024m (堆最大大小)Java Heap最大值,默认值为物理内存的1/4,最佳设值应该视物理内存大小及计算机内其他内存开销而定
-Xmn256m (新生代大小)Java Heap Young区,堆大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
-Xss256k (棧最大深度大小)每个线程的Stack大小,JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。
-XX:SurvivorRatio=8 (新生代分区比例 8:2)
-XX:+UseConcMarkSweepGC (指定使用的垃圾收集器,这里使用CMS收集器)
-XX:+PrintGCDetails (打印详细的GC日志)JDK8之后把-XX:PermSize 和 -XX:MaxPermGen移除了,取而代之的是
-XX:MetaspaceSize=128m (元空间默认大小)
-XX:MaxMetaspaceSize=128m (元空间最大大小)
JDK 8开始把类的元数据放到本地化的堆内存(native heap)中,这一块区域就叫Metaspace,中文名叫元空间。
使用本地化的内存有什么好处呢?最直接的表现就是java.lang.OutOfMemoryError: PermGen 空间问题将不复存在,因为默认的类的元数据分配只受本地内存大小的限制,也就是说本地内存剩余多少,理论上Metaspace就可以有多大,这解决了空间不足的问题。不过,让Metaspace变得无限大显然是不现实的,因此我们也要限制Metaspace的大小:使用-XX:MaxMetaspaceSize参数来指定Metaspace区域的大小。JVM默认在运行时根据需要动态地设置MaxMetaspaceSize的大小。
排查步骤:
1. 通过 ps -aux |grep pid 或者 top -p pid 命令查看项目内存占用情况(我这里是已经优化完的)
RES:resident memory usage 常驻内存
(1)进程当前使用的内存大小,但不包括swap out
(2)包含其他进程的共享
(3)如果申请100m的内存,实际使用10m,它只增长10m,与VIRT相反
(4)关于库占用内存的情况,它只统计加载的库文件所占内存大小
RES = CODE + DATA
VIRT:virtual memory usage
(1)进程“需要的”虚拟内存大小,包括进程使用的库、代码、数据等
(2)假如进程申请100m的内存,但实际只使用了10m,那么它会增长100m,而不是实际的使用量
VIRT = SWAP + RES
2. 可以使用 jmap -dump:format=b,file=文件名 [pid] 导出整个JVM 中内存信息,再使用 jvisualvm 工具进行分析。或者使用 jmap -heap [pid] : 查看整个JVM内存状态。内存使用情况如下:
[root@new-frame-251 texu]# jmap -heap 5847
Attaching to process ID 5847, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.211-b12using parallel threads in the new generation.
using thread-local object allocation.
Concurrent Mark-Sweep GC ##垃圾回收器Heap Configuration:MinHeapFreeRatio = 40MaxHeapFreeRatio = 70MaxHeapSize = 83886080 (80.0MB) ##当前jvm最大堆大小NewSize = 27918336 (26.625MB)MaxNewSize = 27918336 (26.625MB)OldSize = 55967744 (53.375MB)NewRatio = 2SurvivorRatio = 8MetaspaceSize = 21807104 (20.796875MB) ##元空间大小CompressedClassSpaceSize = 1073741824 (1024.0MB)MaxMetaspaceSize = 17592186044415 MB ## 最大元空间大小G1HeapRegionSize = 0 (0.0MB)Heap Usage: ## 当前堆的各个区域使用情况
New Generation (Eden + 1 Survivor Space):capacity = 25165824 (24.0MB)used = 5727184 (5.4618682861328125MB)free = 19438640 (18.538131713867188MB)22.757784525553387% used
Eden Space:capacity = 22413312 (21.375MB)used = 4922248 (4.694221496582031MB)free = 17491064 (16.68077850341797MB)21.961270159448098% used
From Space:capacity = 2752512 (2.625MB)used = 804936 (0.7676467895507812MB)free = 1947576 (1.8573532104492188MB)29.243687220982142% used
To Space:capacity = 2752512 (2.625MB)used = 0 (0.0MB)free = 2752512 (2.625MB)0.0% used
concurrent mark-sweep generation:capacity = 55967744 (53.375MB)used = 48057048 (45.830772399902344MB)free = 7910696 (7.544227600097656MB)85.86561573752195% used28885 interned Strings occupying 3461280 bytes.
[root@new-frame-251 texu]# jstack 5847 |grep tid|wc -l ## 统计线程数,每个线程都有一个 tid
251
[root@new-frame-251 texu]# jstack 5847 |grep java.lang.Thread.State|wc -l ##有几个特殊的线程没有状态
246
[root@new-frame-251 texu]#[root@master159 ~]# jstack 107435 |grep tid |wc -l
259
[root@master159 ~]# jstack 107435|grep 'dubbo-remoting-server-heartbeat' |wc -l
1
[root@master159 ~]# jstack 107435|grep 'DubboServerHandler-10.39.251.159:' |wc -l ##dubbo 线程有点多可以优化
200
[root@master159 ~]# jstack 107435|grep 'http-nio-10065-' |wc -l
14
[root@master159 ~]#
内存使用计算:(Eden )21.375+(扩展区1)2.625+(扩展区2)2.625+(垃圾回收器)53.375+(线程栈)251*0.25=142.8M
再加上 JVM进程本身运行内存+ NIO的DirectBuffer +JIT+JNI+…≈281M (最开始查看的项目占用内存,设置了-Xss256k,所以一个线程占用256k内存),计算出来很正常。
3. 查看进程中各个线程情况:
top -H -p 5847 中的 pid 的16进制转小写 对应的就是 jstack -l 5847 中的 nid 。使用这两个命令就可以查看线程的内存使用,及具体代码情况
4. 前面只是分析了RES 并没有分析 VIRT(虚拟内存),VIRT 分析如下:
使用 pmap -x 5847 查看进程的内存映像信息
这些内存块加起来就是虚拟内存占用的内存情况;
百度:linux为了解决多线程下内存分配竞争而引起的性能问题,增强了动态内存分配行为,使用了一种叫做arena的memory pool,在64位系统下面缺省配置是一个arena大小为64M,一个进程可以最多有cpu cores * 8个arena。假设机器是8核的,那么最多可以有8 * 8 = 64个arena,也就是会使用64 * 64 = 4096M内存。
可以通过设置系统环境变量来改变arena的数量:
MALLOC_ARENA_MAX=8(一般建议配置程序cpu核数)
现代操作系统里面分配虚拟地址空间操作不同于分配物理内存。在64位操作系统上,可用的最大虚拟地址空间有16EB,即大概180亿GB。那么在一台只有16G的物理内存的机器上,我也能要求获得4TB的地址空间以备将来使用
1.VIRT高是因为分配了太多地址空间导致。
2.一般来说不用太在意VIRT太高,因为你有16EB的空间可以使用。
3.如果你实在需要控制VIRT的使用,设置环境变量MALLOC_ARENA_MAX,例如hadoop推荐值为4,因为YARN使用VIRT值监控资源使用。参考:https://www.sohu.com/a/250985880_756465
结束:
以上只是对jvm内存占用情况进行分析,分析完之后,对异常的地方进行优化即可;
参考:
https://blog.csdn.net/zengwende/article/details/103665545
https://www.jianshu.com/p/8d5782bc596e
springboot内存占用过高问题排查 - jvm内存使用分析相关推荐
- linux内存占用过高怎么解决,centos7内存占用过高处理方法
博士有几台frps服务器都出现了内存占用过高的现象,然后会出现CPU使用率飙升,网上找到这个清理buff/cache缓存脚本,希望有效果. 博士在找到这个脚本的时候也学到了一个关于Linux的知识点, ...
- linux下的buff/cache内存占用过高-手动清除释放内存
buff/cache内存占用太高 我们在使用free -h或者(top命令)查看系统内存的时候,有时间会发现buff/cache很高,如下图: [root@nfs ~]# free -htotal u ...
- Linux中buff/cache内存占用过高-手动清除释放内存
buff/cache内存占用太高 我们在使用free -h或者(top命令)查看系统内存的时候,有时间会发现buff/cache很高,如下图 可以看到我总内存就1.8G,buff/cache就占用了1 ...
- java程序内存占用过高问题排查
一.现象 收到线上机器报警(内存使用过高),对报警的机器节点重启后恢复正常,搁天后新的节点又开始报警: 二.排查 直接对线上机器执行dump命令,由于线上机器还有流量在持续请求,因此dump时间比较长 ...
- 记一次Linux系统内存占用较高得排查
背景:收到报警,系统的内存使用率触发阈值(部分图是后补的) 1,登陆系统,使用命令查看内存分配 top 按M free -m atop 看下内存分配(cat /proc/meminfo 也可以看到一些 ...
- UE 手游在 iOS 平台运行时内存占用太高?试试这样着手优化
性能优化,对游戏开发来说是一个需要不断钻研的课题,性能越好,游戏才会运行的更加顺畅,玩家的体验感才会更好.腾讯游戏学院专家.游戏客户端开发 Leonn,将和大家分享 UE 手游在 iOS 平台上的内存 ...
- node启动之后内存占用过高解决方案
小编一开始也是一脸懵,这是为啥呢,一个空的node项目启动之后占用内存竟然有400多M 查看项目占用cpu以及内存详情命令 docker stats | grep node 经过小编坚持不懈的找度年终 ...
- 一次jvm导致线上内存占用过高问题定位
背景:8G物理内存,8核CPU,jvm使用的G1垃圾回收器. 问题:线上内存占用告警,内存占用超过85%,且现象一直持续. 分析 看一下jvm启动参数配置: -Xms6144m -Xmx6144m - ...
- 【jvm内存占用过高分析】
[jvm内存占用过高分析] 1.首先进入服务容器内 //获取服务容器名称 kubectl get pods |grep <服务名称>// 进入容器内部 kubectl -it exec & ...
- Linux系统内存占用过高排查方法
以下以Ubuntu系统为例,内存占用过高可能是因为某个进程或程序占用了过多的内存,您可以按照以下步骤进行排查: 以上是一些基本的排查步骤,它们可以帮助您确定内存占用过高的原因,并采取相应的措施解决问题 ...
最新文章
- java的关键字和保留字_「Java」详解常见的53个关键字
- Android--调用内置的浏览器
- 上线4年从畅销Top 200到Top 20,这款刀塔传奇like卡牌正在美国市场逆流而上
- springboot接收json参数_Springboot + Vue + shiro 实现前后端分离、权限控制
- Sklearn之Ensemble 估计器
- 真我手机信号好还是苹果三星信号好?
- leetcode解题笔记-Summary Ranges
- 22.Linux-块设备驱动之框架详细分析(详解)
- 《GAMES104-现代游戏引擎:从入门到实践》-05 学习笔记
- 手机上最好用的五笔输入法_什么手机输入法最实用?目前最受欢迎的3款盘点,你正在用哪款呢...
- 三天晚上看了24集 央视版《神雕侠侣》 还不错
- 数据结构—双向链表的基本操作
- SRGB和RGB的区别
- 保险行业防范网络犯罪新思路
- lzma java sdk,如何使用LZMA SDK在Java中压缩/解压缩
- [LGP2791] 幼儿园篮球题
- Linux ARM平台开发系列讲解(GMSL摄像头篇)1.2 MAX9296 GMSL链路配置
- Redis数据类型有哪些?
- EDKII实现bmp图片加载并显示的应用程序
- 标准紧固件、垫片、轴环