JVM加载类的时候,须要记录类的元数据,这些数据会保存在一个单独的内存区域内,在Java 7里,这个空间被称为永久代(Permgen),在Java 8里,使用元空间(Metaspace)代替了永久代。永久代和元空间保存的数据并不彻底同样,永久代中还保存另外一些与类的元数据无关的杂项。java
如咱们以前的一篇文章016:字符串对象在JVM中是如何存放的中说的,在Java 7里将字符串常量从永久代移动到了堆区域,可是永久代并无彻底改造完成。直到Java 8,永久代的改造才算彻底搞定,在元空间中保存的数据比永久代中纯粹不少,就是类的元数据,这些信息只对编译期或JVM的运行时有用。面试
使用Java 8之后,关于元空间的JVM参数有两个:-XX:MetaspaceSize=N
和-XX:MaxMetaspaceSize=N
,对于64位JVM来讲,元空间的默认初始大小是20.75MB,默认的元空间的最大值是无限。MaxMetaspaceSize用于设置metaspace区域的最大值,这个值能够经过mxbean中的MemoryPoolBean获取到,若是这个参数没有设置,那么就是经过mxbean拿到的最大值是-1,表示无穷大。后端
因为调整元空间的大小须要Full GC,这是很是昂贵的操做,若是应用在启动的时候发生大量Full GC,一般都是因为永久代或元空间发生了大小调整,基于这种状况,通常建议在JVM参数中将MetaspaceSize和MaxMetaspaceSize设置成同样的值,并设置得比初始值要大,对于8G物理内存的机器来讲,通常我会将这两个值都设置为256M(PS:读者能够根据本身的实际状况再调整)。源码分析
MetaspaceSize表示metaspace首次使用不够而触发FGC的阈值,只对触发起做用,缘由是:垃圾搜集器内部是根据变量_capacity_until_GC
来判断metaspace区域是否达到阈值的,初始化代码以下所示:学习
void MetaspaceGC::initialize() {
// Set the high-water mark to MaxMetapaceSize during VM initializaton since
// we can't do a GC during initialization.
_capacity_until_GC = MaxMetaspaceSize;
}复制代码
GC收集器会在发生对metaspace的回收会,会计算新的capacityuntil_GC值,之后发生FGC就跟MetaspaceSize没有关系了。优化
若是不设置MetaspaceSize,则默认的capacityuntil_GC为20M左右,具体代码以下:***本号专一于后端技术、JVM问题排查和优化、Java面试题、我的成长和自我管理等主题,为读者提供一线开发者的工做和成长经验,期待你能在这里有所收获。spa