一、背景介绍
本篇博客是对生产环境出现内存长期占用导致系统变慢的原因分析及总结。
现状:
系统出现了爬取加载慢的情况,核心服务的内存占用很高的情况。
如下图:
二、思路&方案
查询服务内存占用过高的原因:
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包的时候书写合适的参数,保证程序运行。
四、升华
灰度认知,黑白决策,虽然硬件资源随着摩尔定律的发展成本越来越低,但是这不是我们乱写代码长期占用资源的理由,在看待这个问题的时候我们要对硬件资源成本有一个灰度认知,不能走极端。生活中也是一样,结合现实的不同情况选择不同的方案,用逻辑办事,而不是靠感觉。
内存长期占用导致系统变慢可能是由于内存泄漏或者内存不合理使用引起的。解决这个问题需要以下一些步骤:
内存泄漏检测: 使用工具如内存分析器(如Java中的MAT、Python中的memory_profiler等)来检测内存泄漏。这些工具可以帮助你找到未被释放的内存对象,从而确定是哪些部分导致了内存长期占用。
代码审查: 检查代码,特别是那些与内存管理相关的部分,如对象创建、释放、数据结构的使用等。确保没有未使用的对象或者被遗漏释放的资源。
资源管理: 确保在代码中正确地释放不再使用的资源,如数据库连接、文件句柄等。使用finally块或者资源管理工具来确保资源的正确释放。
缓存和对象池: 如果使用了缓存,确保缓存中的对象可以合理地过期或者被清理。使用对象池来重复使用对象,而不是频繁创建和销毁。
优化数据结构: 使用合适的数据结构,避免使用过于复杂或者低效的数据结构。合理使用集合、映射等数据结构,以减少内存消耗。
分页和分批处理: 如果操作大量数据,尽量采用分页或分批处理的方式,而不是一次性加载所有数据到内存中。
限制资源使用: 如果系统中的某个模块或功能长期占用过多的内存,可以考虑设置资源限制,防止其过度消耗系统资源。
监控和警报: 设置内存使用的监控和警报机制,一旦内存使用超过阈值,及时通知开发人员进行排查和解决。
垃圾回收优化: 针对不同的编程语言,了解其垃圾回收机制,并根据实际情况调整垃圾回收的参数和策略。
水平扩展: 如果系统经常需要大量的内存,考虑进行水平扩展,即增加服务器数量,从而分担内存负担。
定期重启: 在没有找到明显问题原因的情况下,考虑定期重启应用程序,以释放内存和资源。
综合考虑上述方法,你可以逐步定位和解决导致内存长期占用的问题,从而提升系统性能和稳定性。