一、背景介绍
本篇博客是对生产环境出现内存长期占用导致系统变慢的原因分析及总结。
现状:
系统出现了爬取加载慢的情况,核心服务的内存占用很高的情况。
如下图:
二、思路&方案
查询服务内存占用过高的原因:
1、服务启动时分配的堆内存过小(与Xms和Xmx有关,-Xms 为JVM启动时申请的初始Heap值,-Xmx 为JVM运行时可申请的最大Heap值)
2、具有大量大对象被创建,并且没有及时被GC回收或者由于具有引用GC无法回收(代码中存在不合理的地方,需要进行代码调优)
3、当GC之后,虽然会清理堆内的对象看,但是并不会释放内存,没有把曾经申请到的内存归还给操作系统(与垃圾回收器和垃圾回收器的回收机制有关)
解决方案
1、服务启动时分配的堆内存过小
解决方案:修改启动jar包的时候的配置
如:如: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来指定这个比例。
2、大对象被创建但是没有被回收
解决方案:查看代码逻辑存在不合理的地方
方式:我们可以分析dump文件找到内存占用的原因。
首先生成系统快照dump文件:
jmap -dump:[live,]format=b,file=<filename> <pid>
然后通过内存分析工具进行分析:如MAT jvisual
启动jvisual载入下载下来的.hprof文件,之后就可以进行内存分析了。
3、当GC之后,虽然会清理堆内的对象看,但是并不会释放内存,没有把曾经申请到的内存归还给操作系统
解决方案:与垃圾回收器和垃圾回收器的回收机制有关
1、首先jvm明确目前使用的是哪一种垃圾回收器
java -XX:+PrintCommandLineFlags -version
虚拟机运行在Server模式下的默认值,打开此开关后,使用ParallelSeavenge+ParallelOld的收集器组合进行内存回收。
JDK1.8 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
1、目前使用的是的是JDK1.8默认垃圾收集器ParallelSeavenge+ParallelOld
2、可以通过修改配置文件的方式,如更换为G1
三、总结
1、写每一行代码的时候都要思考内存占用问题,能不能缩小变量的作用域。
2、启动jar包的时候书写合适的参数,保证程序运行。
四、升华
灰度认知,黑白决策,虽然硬件资源随着摩尔定律的发展成本越来越低,但是这不是我们乱写代码长期占用资源的理由,在看待这个问题的时候我们要对硬件资源成本有一个灰度认知,不能走极端。生活中也是一样,结合现实的不同情况选择不同的方案,用逻辑办事,而不是靠感觉。