排查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内存使用分析相关推荐

  1. linux内存占用过高怎么解决,centos7内存占用过高处理方法

    博士有几台frps服务器都出现了内存占用过高的现象,然后会出现CPU使用率飙升,网上找到这个清理buff/cache缓存脚本,希望有效果. 博士在找到这个脚本的时候也学到了一个关于Linux的知识点, ...

  2. linux下的buff/cache内存占用过高-手动清除释放内存

    buff/cache内存占用太高 我们在使用free -h或者(top命令)查看系统内存的时候,有时间会发现buff/cache很高,如下图: [root@nfs ~]# free -htotal u ...

  3. Linux中buff/cache内存占用过高-手动清除释放内存

    buff/cache内存占用太高 我们在使用free -h或者(top命令)查看系统内存的时候,有时间会发现buff/cache很高,如下图 可以看到我总内存就1.8G,buff/cache就占用了1 ...

  4. java程序内存占用过高问题排查

    一.现象 收到线上机器报警(内存使用过高),对报警的机器节点重启后恢复正常,搁天后新的节点又开始报警: 二.排查 直接对线上机器执行dump命令,由于线上机器还有流量在持续请求,因此dump时间比较长 ...

  5. 记一次Linux系统内存占用较高得排查

    背景:收到报警,系统的内存使用率触发阈值(部分图是后补的) 1,登陆系统,使用命令查看内存分配 top 按M free -m atop 看下内存分配(cat /proc/meminfo 也可以看到一些 ...

  6. UE 手游在 iOS 平台运行时内存占用太高?试试这样着手优化

    性能优化,对游戏开发来说是一个需要不断钻研的课题,性能越好,游戏才会运行的更加顺畅,玩家的体验感才会更好.腾讯游戏学院专家.游戏客户端开发 Leonn,将和大家分享 UE 手游在 iOS 平台上的内存 ...

  7. node启动之后内存占用过高解决方案

    小编一开始也是一脸懵,这是为啥呢,一个空的node项目启动之后占用内存竟然有400多M 查看项目占用cpu以及内存详情命令 docker stats | grep node 经过小编坚持不懈的找度年终 ...

  8. 一次jvm导致线上内存占用过高问题定位

    背景:8G物理内存,8核CPU,jvm使用的G1垃圾回收器. 问题:线上内存占用告警,内存占用超过85%,且现象一直持续. 分析 看一下jvm启动参数配置: -Xms6144m -Xmx6144m - ...

  9. 【jvm内存占用过高分析】

    [jvm内存占用过高分析] 1.首先进入服务容器内 //获取服务容器名称 kubectl get pods |grep <服务名称>// 进入容器内部 kubectl -it exec & ...

  10. Linux系统内存占用过高排查方法

    以下以Ubuntu系统为例,内存占用过高可能是因为某个进程或程序占用了过多的内存,您可以按照以下步骤进行排查: 以上是一些基本的排查步骤,它们可以帮助您确定内存占用过高的原因,并采取相应的措施解决问题 ...

最新文章

  1. java的关键字和保留字_「Java」详解常见的53个关键字
  2. Android--调用内置的浏览器
  3. 上线4年从畅销Top 200到Top 20,这款刀塔传奇like卡牌正在美国市场逆流而上
  4. springboot接收json参数_Springboot + Vue + shiro 实现前后端分离、权限控制
  5. Sklearn之Ensemble 估计器
  6. 真我手机信号好还是苹果三星信号好?
  7. leetcode解题笔记-Summary Ranges
  8. 22.Linux-块设备驱动之框架详细分析(详解)
  9. 《GAMES104-现代游戏引擎:从入门到实践》-05 学习笔记
  10. 手机上最好用的五笔输入法_什么手机输入法最实用?目前最受欢迎的3款盘点,你正在用哪款呢...
  11. 三天晚上看了24集 央视版《神雕侠侣》 还不错
  12. 数据结构—双向链表的基本操作
  13. SRGB和RGB的区别
  14. 保险行业防范网络犯罪新思路
  15. lzma java sdk,如何使用LZMA SDK在Java中压缩/解压缩
  16. [LGP2791] 幼儿园篮球题
  17. Linux ARM平台开发系列讲解(GMSL摄像头篇)1.2 MAX9296 GMSL链路配置
  18. Redis数据类型有哪些?
  19. EDKII实现bmp图片加载并显示的应用程序
  20. 标准紧固件、垫片、轴环

热门文章

  1. 常见的十二种逻辑谬误
  2. JS 案例 改变网页背景颜色
  3. 基于51单片机的DHT11传感器
  4. 论文参考文献生成以及标注方法说明
  5. 【C语言】案例五十一 员工档案管理系统
  6. 关于IPad忘记密码恢复出厂设置的办法
  7. 探究达梦8中索引数量与磁盘占用,查询和dml的小实验
  8. Python+Flask(2)--通过flask paginate解决列表分页问题
  9. 前端改好,验证码显示不出来!!
  10. java里直线绕z轴逆时针旋转_空间直线绕任意轴旋转后的方程