一、场景
线上项目device服务模块内存不断上涨导致CPU较高,导致触发脚本执行重启,接口自动化测试平台不断的报500拒绝连接等错误提示。
排查:
通过服务器日志查询并没有异常错误信息打印,查看docker容器的日志发现错误是打印控制台,无法从控制台中找到有价值的日志
短暂方案解决:
内存溢出问题因为JVM内存分配不够大导致的,调大JVM的内存可以短暂解决此问题,但解决不了根本问题,需要从代码层去定位排查
二、Java启动参数分析(调试参数)
调试参数列表:
参数及其默认值 | |
-XX:-CITime | 打印消耗在JIT编译的时间 |
-XX:ErrorFile=./hs_err_pid<pid>.log | 保存错误日志或者数据到文件中 |
-XX:-ExtendedDTraceProbes | 开启solaris特有的dtrace探针 |
-XX:HeapDumpPath=./java_pid<pid>.hprof | 指定导出堆信息时的路径或文件名 |
-XX:-HeapDumpOnOutOfMemoryError | 当首次遭遇OOM时导出此时堆中相关信息 |
-XX:OnError="<cmd args>;<cmd args>" | 出现致命ERROR之后运行自定义命令 |
-XX:OnOutOfMemoryError="<cmd args>;<cmd args>" | 当首次遭遇OOM时执行自定义命令 |
-XX:-PrintClassHistogram | 遇到Ctrl-Break后打印类实例的柱状信息,与jmap -histo功能相同 |
-XX:-PrintConcurrentLocks | 遇到Ctrl-Break后打印并发锁的相关信息,与jstack -l功能相同 |
-XX:-PrintCommandLineFlags | 打印在命令行中出现过的标记 |
-XX:-PrintCompilation | 当一个方法被编译时打印相关信息 |
-XX:-PrintGC | 每次GC时打印相关信息 |
-XX:-PrintGC Details | 每次GC时打印详细信息 |
-XX:-PrintGCTimeStamps | 打印每次GC的时间戳 |
-XX:-TraceClassLoading | 跟踪类的加载信息 |
-XX:-TraceClassLoadingPreorder | 跟踪被引用到的所有类的加载信息 |
-XX:-TraceClassResolution | 跟踪常量池 |
-XX:-TraceClassUnloading | 跟踪类的卸载信息 |
-XX:-TraceLoaderConstraints | 跟踪类加载器约束的相关信息 |
三、项目配置启动参数
1、打开docker-compose.yaml,进行编辑
1、表示JVM启动运行内存的配置
2、表示当前配置首次遭遇OOM时导出此时堆中相关信息
3、表示运行的jar
4、表示运行所指向的配置
只要发生OOM,就会将对应的堆文件导出,可以根据堆文件进行问题排查
四、MAT工具使用
是一个快速且功能丰富的Java堆分析器,可以定位排查内存泄漏的问题
1、安装独立版本的MAT
下载压缩包解压到本地文件夹中,解压完就可以直接使用,双击运行
下载地址:http://www.eclipse.org/mat/downloads.php
2、从生产环境将导出的dump内存快照文件存在本地
3、导入dump的文件
4、分析
Shallow Heap浅堆:java对象占用的内存
Retained Heap深堆:java对象及对象引用的类占用的内存 ,jvm gc回收时释放的内存
Retained Heap深堆大于等于Shallow Heap浅堆
5、定位代码抛出抛出异常分析
从这个报错线程里面我们可以发现关键的几个类或者几个方法:
com.seirobotics.device.service.task.ThreadExportCsvData.exportCsvData()V (ThreadExportCsvData.java:74)
com.seirobotics.device.service.impl.DeviceFromMongoServiceImpl.getDeviceStatusBySns(Ljava/util/List;Ljava/lang/String;)Ljava/util/List; (DeviceFromMongoServiceImpl.java:455)
org.springframework.data.mongodb.core.MongoTemplate.find(Lorg/springframework/data/mongodb/core/query/Query;Ljava/lang/Class;Ljava/lang/String;)Ljava/util/List; (MongoTemplate.java:823)
通过以上的排查,我们已经定位到代码的报错的位置,最后我们再回归代码进行检测代码,然后找到问题点进行改正。
重点:通过配置ymal文件,产生内存溢出时,会自动将堆文件给导出到服务器,通过堆文件去排查定位问题