内存长期占用导致系统慢
一:背景介绍
本篇博客是对生产环境出现内存长期占用系统慢的分析以及总结。目的是将经历转变为自己的经验。通过博客的方式分享给大家,大家一起共同进步和提高。
出现的问题
目前又出现了爬取加载慢的情况,核心服务的内存占用很高的情况。
二:思路&方案
服务内存占用过高的原因:
1.服务启动时分配的堆内存过小(与Xms和Xmx有关,-Xms 为JVM启动时申请的初始Heap值,-Xmx 为JVM运行时可申请的最大Heap值)
2.具有大量大对象被创建,并且没有及时被GC回收或者由于具有引用GC无法回收(代码中存在不合理的地方,需要进行代码调优)
3.当GC之后,虽然会清理堆内的对象看,但是并不会释放内存,没有把曾经申请到的内存归还给操作系统(与垃圾回收器和垃圾回收器的回收机制有关)
下面是对于这三个原因的解决方案
1.服务启动时分配的堆内存过小
我们可以通过在启动jar文件的时候进行Xms和Xmx的配置
如:nohup java -Xms3072m -Xmx4096m -jar a.jar&
-Xms 为JVM启动时申请的初始Heap值,默认为操作系统物理内存的1/64但小于1G。默认当空余堆内存大于70%时,JVM会减小heap的大小到-Xms指定的大小,可通过-XX:MaxHeapFreeRation来指定这个比列。
-Xmx 为JVM运行时可申请的最大Heap值,默认值为物理内存的1/4但小于1G,默认当空余堆内存小于40%时,JVM会增大Heap到-Xmx指定的大小,可通过-XX:MinHeapFreeRation来指定这个比列。
nohup 不挂断的运行
& 指后台运行
2. 具有大量大对象被创建,并且没有及时被GC回收或者由于具有引用GC无法回收
这类问题是由于代码存在不合理的情况,需要进行代码调优。我们可以分析dump文件找到内存占用的原因。
首先生成系统快照dump文件:
执行命令:
jmap -dump:[live,]format=b,file=<filename> <pid>
通过-dump选项,把java堆中的对象dump到本地文件,pid为进程号
然后通过内存分析工具进行分析:如MATjvisual
示例: 使用jvisual分析dump文件,这个是jdk1.8自带的分析工具
启动jvisual载入下载下来的.hprof文件,之后就可以进行内存分析了。
3.当GC之后,虽然会清理堆内的对象看,但是并不会释放内存,没有把曾经申请到的内存归还给操作系统
这个主要与垃圾回收器和垃圾回收器的回收机制有关
首先jvm明确目前使用的是哪一种垃圾回收器
cmd中输入以下命令:
java -XX:+PrintCommandLineFlags -version
虚拟机运行在Server模式下的默认值,打开此开关后,使用ParallelSeavenge+ParallelOld的收集器组合进行内存回收。
JDK1.8 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
目前已有的结论是full gc操作之后物理内存没有下降的原因与垃圾回收器回收的物理内存归还机制有关。
目前了解到1.CMS垃圾回收器,在内存开辟后,会随着System.gc()执行次数逐渐增多和回收频率逐渐拉长,从继续开辟内存到慢慢归还物理内存给操作系统,直到出现一次全部归还,就会在每次调用System.gc()都归还所有剩余的物理内存给操作系统;G1恰恰相反,G1是在JVM每次回收垃圾后,主动归还物理内存给操作系统,不做任何保留,大大降低了内存占用。
2.咱们目前使用的垃圾回收器的是ParallelSeavenge+ParallelOld
3.可以通过修改配置的方式更换垃圾回收器,如更换为G1
下一步的计划是了解ParallelSeavenge+ParallelOld物理内存归还机制.
选择更适合系统的垃圾回收器。
四:总结
由于出现内存长期占用导致系统慢这个问题是很早之前出现,现在进行复现比较困难。所以采取的是对于可能出现情况的一个分析,并没有深入的分析原因。
通过这次的分析,对于有与代码质量的原因造成的内存飙升问题,一方面可以通过代码质量进行解决,另一方面也可以通过压力测试的方式进行测试,避免由于代码原因导致内存飙升,并且居高不下。
另一方面,关于垃圾回收器的选择需要结合到实际情况进行选择
五:升华
博客中相当一部分内容是之间自己处理内存飙升和内存泄露的总结笔记。但是但是并没有进行及时总结导致还是缺很多东西。及时总结还真是一个事。进行及时总结,1+n,n+1。