原视频链接:不存在的网站,翻译此视频并发布已获得原作者同意。
目录
- Java进程的内存占用[译] Part 2 - Andrei Pangin
- JVM 运行时 - 类加载
Java进程的内存占用[译] Part 2 - Andrei Pangin
JVM 运行时 - 类加载
好了,我们讲完Java堆和GC,接下来是类加载,这是另外一个子系统,NMT报告中也有关于这方面的统计信息。
在JDK10之后,Class部分的报告会多一些,包含了Metadata和Class space两部分,那么他们是什么呢?
各位读者有听过Metaspace和Metadata吗?我想很多人都听过。基本上,元数据就是类文件解析的结果,在JDK8之前,Metadata包含在PermGen,PermGen可以进行大小的调整。在PermGen溢出时,你能看到报错OutOfMemoryError: PermGen space。但是现在,这些元数据都被放在了Metaspace。
默认情况下这个区域是无限大的。
每个Java对象在Metaspace中都有一个指针,当JVM堆内存小于32G时,JVM默认会启用CompressedOops(压缩指针)优化,这个优化让对象引用占用32bit,而不是64bit。另外,通过启用UseCompressedClassPointers这个选项,也是默认启用的,将能够把每个对象的类的指针压缩为32bit,当这个选项开启时,元数据被从Metaspace转移到另一个区域:Compressed class space(压缩类空间)。
这个Compressed class space是大小受限的,默认1G,最大3G。问题来了,如果你的应用程序载入了太多的类,你将能看到:OutofMemoryError: Compressed class space 异常。
好了,当你看到这样的异常,怎么分析Metaspace的使用量呢?你可以打印classloader(类加载器)的统计信息,通过一个很有用的工具:jcmd,在这个案例中,我们看到一个名为XXGenerator的类加载器,加载了100000个类,使用大小超过了80M。
甚至可以更进一步,查看详细的统计信息,查看每个类的方法、字段、注解使用了多少内存。
如何限制Metaspace 的内存使用呢?首先这里有两个选项:-XX:MaxMetaspaceSize(包含CompressedClassSpaceSize)、-XX:CompressedClassSpaceSize。
另外一个JVM选项,经常出现误解的是:-XX:MetaspaceSize,设置的既不是初始化,也不是最小化的大小,而是高水位线,当达到水位线后,GC 循环被触发,所以如果你看到GC日志中有类似这样的信息:[Full GC (Metadata GC Threshold) 1032K->894K(198656K), 0.077995 secs],就要注意是达到水位线了。
Metaspace可以配置在何种比例时,进行扩容和缩容,通过配置这两个选项:-XX:MinMetaspaceFreeRatio、-XX:MaxMetaspaceFreeRatio。
以上就是Metaspace的所有内容了。