问题
kettle数据采集系统崩溃-查看报错信息为:
OutOfMemoryError: Compressed class space
可以看到是内存溢出,但是可以看到的后面的信息为 Compressed class space ,而不是java heap。
Compressed class space为压缩类空间, 这个空间是保存在64位系统中类引用地址的空间,默认大小为1G,单个类引用地址的空间是1K
意味着加载的类已经超过1百万,这肯定是存在问题的,需要进一步查找问题。
内存dump
将系统当时的内存情况dump下来进行分析
jmap
java自带visualVM,jmap等分析工具可以直接使用
将当前系统活跃的内存数据写入到kettle-test-dump-03020941.hprof 文件中,系统pid为18090
jmap -dump:live,format=b,file=./kettle-test-dump-03020941.hprof 18090
在实际使用时,发现jdk是openjdk,并未自带jmap等工具,可以进行升级.但是怕影响系统运行,另外下载了一个jdk使用
分析
使用工具进行分析,下面介绍两种工具进行查看,java自带的jvisualVM和IBM HeapAnalyzer:
jvisualVM不需要下载,但是不会自行统计,需要自己写sql来进行深度分析
IBM HeapAnalyzer提供表格,饼图的方式,更加直观的看到数据,并且会分析出最可能发生内存泄漏的地方
jvisualVM
使用本地jdk自带的visualVM来进行分析查看
-
下载hprof文件到本地
-
找到jdk目录,找到 bin/jvisualvm.exe ,双击打开,界面如下:
-
导入文件 点击 文件->装入->切换到dump文件 ->找到hprof文件打开
- 点开类视图,过滤出classload ,并根据classload 找到对应的示例和加载类的个数,数据不太直观,但是统计后可以看出问题出在/org/pf4j/PluginClassLoader,根据此信息查找bug出现的原因。
IBM HeapAnalyzer
本来想使用MAT,但是官网的下载太慢等不起,正好同事安利,就使用了这个:IBM HeapAnalyzer
ha457.jar
- 下载hprof文件到本地
- 打开程序 找到ha457.jar包目录
java -jar ha457.jar
打开后可以看到以下界面
-
打开下载的文件
-
查找类加载项
上图中有三个表格,第一个是加载器类型表格(包括加载器类型,加载器实例数,加载器加载的类的数量),第二个表格是单种加载器的每个实例,以及加载的数量,第三个是每个加载器实例加载的类
可以看到 /org/pf4j/PluginClassLoader 的加载器实例有1千多个,类加载有17万个,大概可以判定是异常数据。等待一段时间后再dump下内存,发现加载的类达到30几万,判断内存溢出就是由这个加载器不断加载类却不释放导致。
根据第三个表格可以找到对应的类,查找到具体原因。