项目实战典型案例20——内存长期占用导致系统慢

简介: 项目实战典型案例20——内存长期占用导致系统慢

内存长期占用导致系统慢

一:背景介绍

本篇博客是对生产环境出现内存长期占用系统慢的分析以及总结。目的是将经历转变为自己的经验。通过博客的方式分享给大家,大家一起共同进步和提高。

出现的问题

目前又出现了爬取加载慢的情况,核心服务的内存占用很高的情况。



二:思路&方案

服务内存占用过高的原因:

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。

目录
相关文章
|
存储 编译器 Go
Go 语言内存逃逸案例
Go 语言内存逃逸案例
61 0
|
15天前
|
存储 缓存 监控
Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
本文介绍了Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
49 7
|
3月前
|
NoSQL 程序员 Linux
轻踩一下就崩溃吗——踩内存案例分析
踩内存问题分析成本较高,尤其是低概率问题困难更大。本文详细分析并还原了两个由于动态库全局符号介入机制(it's a feature, not a bug)触发的踩内存案例。
|
7月前
|
Java
堆内存的溢出案例分析
堆内存的溢出案例分析
32 0
|
7月前
|
存储 负载均衡 算法
负载均衡案例:如何只用2GB内存统计20亿个整数中出现次数最多的整数
负载均衡案例:如何只用2GB内存统计20亿个整数中出现次数最多的整数
115 2
|
7月前
|
缓存 Dubbo Java
案例 1: 某财险承保系统内存泄漏问题
案例 1: 某财险承保系统内存泄漏问题
|
21天前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
169 1
|
11天前
|
存储 监控 算法
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。
|
20天前
|
Java
JVM内存参数
-Xmx[]:堆空间最大内存 -Xms[]:堆空间最小内存,一般设置成跟堆空间最大内存一样的 -Xmn[]:新生代的最大内存 -xx[use 垃圾回收器名称]:指定垃圾回收器 -xss:设置单个线程栈大小 一般设堆空间为最大可用物理地址的百分之80