“jmap –permstat”会展现类加载器的统计数据,比如类加载器、类加载器所加载的类的数量以及这些类加载已死亡还是尚在存活。它还会告诉我们PermGen中interned字符串的总数,以及所加载的类及其元数据所占用的字节数。如果我们要确定是什么内容占满了PermGen,那么这些信息是非常有用的。如下是一个示例的输出,展现了所有的统计信息。在列表的最后一行我们能够看到有一个总数的概述。
$ jmap -permstat 29620
Attaching to process ID 29620, please wait...
Debugger attached successfully. Client compiler detected.
JVM version is 24.85-b06
12674 intern Strings occupying 1082616 bytes. finding class loader instances ..
done. computing per loader stat ..done. please wait.. computing liveness.........................................done.
class_loader classes bytes parent_loader alive? type
<bootstrap> 1846 5321080 null live <internal>
0xd0bf3828 0 0 null live sun/misc/Launcher$ExtClassLoader@0xd8c98c78
0xd0d2f370 1 904 null dead sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0c99280 1 1440 null dead sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0b71d90 0 0 0xd0b5b9c0 live java/util/ResourceBundle$RBClassLoader@0xd8d042e8
0xd0d2f4c0 1 904 null dead sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0b5bf98 1 920 0xd0b5bf38 dead sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0c99248 1 904 null dead sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0d2f488 1 904 null dead sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0b5bf38 6 11832 0xd0b5b9c0 dead sun/reflect/misc/MethodUtil@0xd8e8e560
0xd0d2f338 1 904 null dead sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0d2f418 1 904 null dead sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0d2f3a8 1 904 null dead sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0b5b9c0 317 1397448 0xd0bf3828 live sun/misc/Launcher$AppClassLoader@0xd8cb83d8
0xd0d2f300 1 904 null dead sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0d2f3e0 1 904 null dead sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0ec3968 1 1440 null dead sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0e0a248 1 904 null dead sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0c99210 1 904 null dead sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0d2f450 1 904 null dead sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0d2f4f8 1 904 null dead sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0e0a280 1 904 null dead sun/reflect/DelegatingClassLoader@0xd8c22f50
total = 22 2186 6746816 N/A alive=4, dead=18 N/A
从Java 8开始,jmap –clstats <pid>命令能够打印类加载器及其存活性的类似信息,不过它所展现的是Metaspace中已加载的类的数量和大小,而不再是PermGen。
jmap -clstats 26240
Attaching to process ID 26240, please wait...
Debugger attached successfully. Server compiler detected. JVM version is 25.66-b00 finding class loader instances ..done. computing per loader stat ..done. please wait.. computing liveness.liveness analysis may be inaccurate ...
class_loader classes bytes parent_loader alive? type
<bootstrap> 513 950353 null live <internal>
0x0000000084e066d0 8 24416 0x0000000084e06740 live sun/misc/Launcher$AppClassLoader@0x0000000016bef6a0
0x0000000084e06740 0 0 null live sun/misc/Launcher$ExtClassLoader@0x0000000016befa48
0x0000000084ea18f0 0 0 0x0000000084e066d0 dead java/util/ResourceBundle$RBClassLoader@0x0000000016c33930
total = 4 521 974769 N/A alive=3, dead=1 N/A
正如我们在前面的章节所提到的,Eclipse MAT、jhat、Java VisualVM、JOverflow JMC插件和Yourkit这些工具都能分析堆转储文件,从而分析排查OutOfMemoryError。在解决PermGen和Metaspace的内存问题时,堆转储同样是有用的。Eclipse MAT提供了一个非常好的特性叫做“Duplicate Classes”,它能够列出被不同的类加载实例多次加载的类。由不同的类加载器加载数量有限的重复类可能是应用设计的一部分,但是,如果它们的数量随着时间推移不断增长的话,那么这就是一个危险的信号,需要进行调查。应用服务器托管多个应用时,它们运行在同一个JVM中,如果多次卸载和重新部署应用的话,经常会遇到这种状况。如果被卸载的应用没有释放所有它创建的类加载器的引用,JVM就不能卸载这些类加载器所加载的类,而新部署的应用会使用新的类加载器实例重新加载这些类。