面试:JDK8的元空间存储什么内容?会发生FGC吗?

先来看张图(JVM线程模型):

image-20220616104103703.png

在jdk1.8之前,还有一个分区叫做方法区,它是堆内存的一个逻辑分区。主要用于存储虚拟机加载的类信息、常量、静态变量,以及编译器编译后的代码等数据。为了与堆做区分,方法区还有个名字叫“非堆”,也有人用“永久代”(HotSpot对方法区的实现方法)来表示方法区。

在jdk1.8中,方法区已经不存在,原方法区中存储的类信息、编译后的代码数据等已经移动到了元空间(MetaSpace)中,元空间并没有处于堆内存上,而是直接占用的本地内存。

元空间的大小仅受本地内存限制,但可以通过-XX:MetaspaceSize和-XX:MaxMetaspaceSize来指定元空间的大小。

去永久代的原因有:
  • 字符串存在永久代中,容易出现性能问题和内存溢出。

  • 类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。

  • 永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。

默认的MetaspaceSize大小是多少呢?怎么查看正在运行的java进程的MetaspaceSize呢?

通过以下命令可以查看:

java -XX:+PrintFlagsInitial
# 输出结果:

uintx MaxMetaspaceFreeRatio = 70 {product}
uintx MaxMetaspaceSize = 18446744073709551615 {product}
uintx MetaspaceSize = 21810376    {pd product}

jmap -heap pid
# (由于设置了参数-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m)
# 输出以下结果:
Heap Configuration:
   MetaspaceSize            = 268435456 (256.0MB)
   MaxMetaspaceSize         = 268435456 (256.0MB)
如果使用默认的MetaspaceSize大小会出现什么问题?如何调优?

首先MetaspaceSize的默认大小为21M,如果我们的项目文件过多,在我们应用进程启动的时候就可以看到发生FGC。这里可以通过调整-XX:MetaspaceSize这个参数减少启动的FGC。

另一种情况是我们Java应用很多都是通过动态代理实现一些功能动态代理就要产生运行时编译的代理类,这样就会占用到Metaspace;如果这个参数不调整同样会发生FGC。

还有就是MaxMetaspaceSize参数如果不设置,会使用机器自身内存,如果程序存在内存泄漏,会导致机器内存不足,需要设置一个合理的值来满足应用正常运行。

总结:元空间(Metaspace)里存的是静态变量、常量、加载的类信息、动态编译的代码;这里要注意默认大小如果超过会发生FGC,而我们调优的目的就是尽量不产生FGC;需要通过-XX:MetaspaceSize这个参数设置来避免产生FGC。

-------------欢迎各位留言交流,如有不正确的地方,请予以指正。【Q:981233589】

你可能感兴趣的:(面试:JDK8的元空间存储什么内容?会发生FGC吗?)