对于一个被加载到虚拟机中的类,Metaspace需要分配class和no-class空间
最大的一部分是 Klass 结构,它是固定大小的。
然后紧跟着两个可变大小的 vtable 和 itable,前者由类中方法的数量决定,后者由这个类所实现接口的方法数量决定。
随后是一个 map,记录了类中引用的 Java 对象的地址,尽管该结构一般都很小,不过也是可变的。
vtable 和 itable 通常也很小,但是对于一些巨大的类,它们也可以很大,一个有 30000 个方法的类,vtable 的大小会达到 240k,如果类派生自一个拥有 30000 个方法的接口,也是同理。但是这些都是测试案例,除了自动生成代码,你从来不会看到这样的类。
深入 Non-Class Space
这个区域有很多的东西,下面这些占用了最多的空间:
常量池,可变大小;
每个成员方法的 metadata:ConstMethod 结构,包含了好几个可变大小的内部结构,如方法字节码、局部变量表、异常表、参数信息、方法签名等;
运行时数据,用来控制 JIT 的行为;
注解
对于正常的类(我们假设通过 bootstrap 和 app 加载的类是正常的),我可以得到平均每个类需要约 5-7k 的 Non-Class Space 和 600-900 bytes 的 Class Space。
那么,你应该将 MaxMetaspaceSize 设置为多大呢? 首先应该是计算预期的 Metaspace 使用量。你可以使用上面给出的数字,然后给每个类约 1K 的 Class Space 和 3~8K 的 Non-Class Space 作为缓冲。
因此,如果你的应用程序计划加载10000个类,那么从理论上讲,你只需要 10M 的 Class Space 和 80M Non-Class Space。
然后,你需要考虑安全系数。在大多数情况下,因子 2 是比较安全的。你当然也可以碰运气,设置低一点,但是要做好在碰到 OOM 后调大 Metaspace 空间的准备。
结论
如果设置安全因子为 2,那么需要 20M 的 Class Space 和 160M 的 Non-Class Space,也就是总大小为 180M。因此,在这里-XX:MaxMetaspaceSize=180M是一个很好的选择。
网友评论