应用程序内存泄漏问题排查--运维排查技巧
admin
2023-02-23 15:00:09
0


                                                                        应用程序内存泄漏问题排查        


1.文章的由来;

 在日常运维过程中,会遇到服务器资源居高不下,或者CPU内存暴涨问题而引发的oom导致服务不可用 (大多数程序都是java应用),由此编写了该文章,为工作排查问题参考依据和快速定位问题方法;


2.基础知识储备;

   (1).jvm 配置常见参数:

 堆参数参数

参数
 描述
-Xms  设置 JVM启动时堆内存的初始化大小
-Xmx 设置堆内存最大值
-Xmn 设置年轻代的空间大小,剩下的为年老代的空间大小
-XX:PermGen 设置永久代的内存初始化大小(JDK1.8 开始废弃永久代)
-XX:MaxPermGen 设置永久代的最大值
-XX:SurvivorRatio   设置Eden区和Survivor区的空间比例:Eden/S0 =Eden/S1 默认8
-XX:NewRatio 设置年老代和年轻代的比例大小,默认值是2

回收器参数

-XX:+UseSerialGC    
串行,young (年轻区)和Old(老年区)都使用串行,使用复制算法回收,逻辑简单高效,无现场切换开销
-XX:+UseParallelGC并行, young (年轻区)使用 Parallel scavenge 回收算法,会产生多个线程并行回收。通过-XX:ParallelGCThreads=n 参数指定有线程数,默认为cpu核数,Old(老年区):单线程
-XX:+UseParallelOldGC并行 和UseParallelGC 一样,young (年轻区) 和Old(老年区) 垃圾回收都使用多线程收集
-XX:+UseConMarkSweepGC
并发,短暂停顿的并发收集,young区可以使用普通的或者parallel垃圾回收算法,由参数 --XX:+UseParNewGC 来控制; Old区 只使用Concurrent Mark Sweep
-XX:+UseG1GC
并行的,并发的和增量式短暂停顿的垃圾收集器。不区分young (年轻区) 和Old(老年区)空间。它把堆空间分为多个大小相等的区域。当进行垃圾收集时,他会优先收集存活对象较少的区域。因此叫"Garbage First”

如上表所示,目前主要有串行、并行和并发三种,对于大内存的应用而言,串行的性能太低,因此使用到的主要是并行和并发两种。并行和并发 GC 的策略通过 UseParallelGC 和 UseConcMarkSweepGC 来指定,还有一些细节的配置参数用来配置策略的执行方式。例如:XX:ParallelGCThreads, XX:CMSInitiatingOccupancyFraction 等。 通常:Young 区对象回收只可选择并行(耗时间),Old 区选择并发(耗 CPU)。


项目中可参考常用配置

应用程序内存泄漏问题排查--运维排查技巧


生产环境服务配置参数

 

    系统版本
cpumemjdk 版本jvm配置备注




CentOS 7.5.1804 (Core) 





8C





8G





java-1.8.0_121


java  -Xmx5g -Xms5g -Xmn3g -XX:MetaspaceSize=32m -XX:MaxMetaspaceSize=128m -XX:MaxDirectMemorySize=512m -XX:+UseCompressedClassPointers -XX:CompressedClassSpaceSize=64m -XX:+UseConcMarkSweepGC -XX:ParallelCMSThreads=2 -XX:+CMSClassUnloadingEnabled -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=80 -verbose:gc -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -XX:+PrintTenuringDistribution -XX:+PrintCommandLineFlags -XX:+ExplicitGCInvokesConcurrent -Xloggc:/data/log/app-web/gc.log -Dapp.id=app-web -Dapollo.bootstrap.enabled=true -Duser.timezone=GMT+8 -Dapollo.bootstrap.namespaces=application -Deureka.instance.metadata-map.zone=zone-1 -Dservice.name=app-web -Denv=prod -Dprod_meta=http://configserver-prod.com -Druntime.env=prod -jar ./lib/app-web-1.8.10.0.jar





  微服务

springcloud 框架


常见组合


应用程序内存泄漏问题排查--运维排查技巧

GC 调优原则

在调优之前,我们需要记住下面的原则:


多数的 Java 应用不需要在服务器上进行 GC 优化;

多数导致 GC 问题的 Java 应用,都不是因为我们参数设置错误,而是代码问题;

在应用上线之前,先考虑将机器的 JVM 参数设置到最优(最适合);

减少创建对象的数量;

减少使用全局变量和大对象;

GC 优化是到最后不得已才采用的手段;

在实际使用中,分析 GC 情况优化代码比优化 GC 参数要多得多。

GC 调优目的

将转移到老年代的对象数量降低到最小;

减少 GC 的执行时间。

策略 1:将新对象预留在新生代,由于 Full GC 的成本远高于 Minor GC,因此尽可能将对象分配在新生代是明智的做法,实际项目中根据 GC 日志分析新生代空间大小分配是否合理,适当通过“-Xmn”命令调节新生代大小,最大限度降低新对象直接进入老年代的情况。

策略 2:大对象进入老年代,虽然大部分情况下,将对象分配在新生代是合理的。但是对于大对象这种做法却值得商榷,大对象如果首次在新生代分配可能会出现空间不足导致很多年龄不够的小对象被分配的老年代,破坏新生代的对象结构,可能会出现频繁的 full gc。因此,对于大对象,可以设置直接进入老年代(当然短命的大对象对于垃圾回收老说简直就是噩梦)。-XX:PretenureSizeThreshold 可以设置直接进入老年代的对象大小。

策略 3:合理设置进入老年代对象的年龄,-XX:MaxTenuringThreshold 设置对象进入老年代的年龄大小,减少老年代的内存占用,降低 full gc 发生的频率。

策略 4:设置稳定的堆大小,堆大小设置有两个参数:-Xms 初始化堆大小,-Xmx 最大堆大小。

策略5:注意: 如果满足下面的指标,则一般不需要进行 GC 优化:

MinorGC 执行时间不到50ms;

Minor GC 执行不频繁,约10秒一次;

Full GC 执行时间不到1s;

Full GC 执行频率不算频繁,不低于10分钟1次。

3.排查技巧战


1.内存泄漏排查技巧


系统命令

1.登陆探测服务器,首先是 top free df 三连;


jstat

jstat 是一个非常强大的 JVM 监控工具,一般用法是:jstat [-options] pid interval

它支持的查看项有:

  • -class 查看类加载信息

  • -compile 编译统计信息

  • -gc 垃圾回收信息

  • -gcXXX 各区域 GC 的详细信息 如 -gcold


3. jstat -gc pid [interval] 查看  java 进程的 GC 状态;

关注指标: FULL GC 。


应用程序内存泄漏问题排查--运维排查技巧


4. jstack pid > jstack.log 查询线程栈 并保存现场;

分析栈

栈的分析很简单,看一下线程数是不是过多,多数栈都在干嘛。

> grep 'java.lang.Thread.State' jstack.log  | wc -l
> 464

过滤进程

grep -A 1 'java.lang.Thread.State' jstack.log  | grep -v 'java.lang.Thread.State' | sort | uniq -c |sort -n

    10     at java.lang.Class.forName0(Native Method)
    10     at java.lang.Object.wait(Native Method)
    16     at java.lang.ClassLoader.loadClass(ClassLoader.java:404)
    44     at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
   344     at sun.misc.Unsafe.park(Native Method)


线程状态好像也无异常,接下来分析堆文件。


内存堆dump  

5.使用 jmap -dump:format=b,file=heap.log pid 保存了堆现场,然后重启了应用服务

堆文件都是一些二进制数据,在命令行查看非常麻烦,Java 为我们提供的工具都是可视化的,Linux 服务器上又没法查看,那么首先要把文件下载到本地。

由于我们设置的堆内存为 4G,所以 dump 出来的堆文件也很大,下载它确实非常费事,不过我们可以先对它进行一次压缩。=

gzip 是个功能很强大的压缩命令,特别是我们可以设置 -1 ~ -9 来指定它的压缩级别,数据越大压缩比率越大,耗时也就越长,推荐使用 -6~7, -9 实在是太慢了,且收益不大,有这个压缩的时间,多出来的文件也下载好了。


使用 MAT 分析 jvm heap

MAT 是分析 Java 堆内存的利器,使用它打开我们的堆文件(将文件后缀改为 .hprof), 它会提示我们要分析的种类,果断选择 memory leak suspect。

windows 系统安装包如下:

https://www.eclipse.org/downloads/download.php?file=/mat/1.9.1/rcp/MemoryAnalyzer-1.9.1.20190826-win32.win32.x86_64.zip

应用程序内存泄漏问题排查--运维排查技巧


应用程序内存泄漏问题排查--运维排查技巧








相关内容

热门资讯

携程被罚没51.79亿元 7月25日,市场监管总局依法对携程集团有限公司(以下简称携程)滥用市场支配地位实施垄断行为作出行政处...
多地停运停航停课,台风“红霞”... 中央气象台7月25日06时继续发布台风橙色预警:今年第12号台风“红霞”已于今天(25日)早晨由强热...
“直-20家族”全亮相 近日,在陆军某旅直升机分队演训中,直-20与直-20T表现亮眼。075型两栖攻击舰日前也搭载直-20...
蒋万安借“725上凯道”成蓝营... 中国国民党25日将于台北凯道举办“我是人,我反毒台”集会,向民进党当局抗议中联毒油案。对此,资深媒体...
波轮式全自动洗衣机脱水时波轮转 波轮式全自动洗衣机脱水时波轮转1、衣物放置不平导致;2、排水系统发生阻塞。3、顶部的安全开关损坏;4...
洗衣机不出水怎么查原因 当洗衣机不出水时,一定是出了问题。下面就是一些可能的原因及其解决方法:1. 电源问题洗衣机不能正常工...
半自动洗衣机放不出水是什么原因... 1、检查过滤网是否堵塞。若堵塞了需要将脏东西取出来,然后再用清水将过滤网清洗干净。2、检查一下是不是...
全自动洗衣机不出水是什么原因 1、进水口的滤网被水中的杂质堵住。2、控制板上的进水继电器坏了。3、电路故障,进水电磁阀有故障或者插...
抽油烟机只通电不转怎么回事 只通电不转的故障原因和解决方法:1、电容量减小或损坏。解决方法:抽油烟机电机不转,还有嗡嗡声,一般是...
谷歌被罚9亿欧元后,特朗普称欧... 当地时间7月23日,欧盟委员会指控美国谷歌公司违反欧盟《数字市场法》,对其处以8.9亿欧元罚款。这一...