为什么 jmap -permstat 会报告超过使用的 MaxPermSize 字节数?

Why would jmap -permstat report more than MaxPermSize bytes used?

我获取了 JVM 的 jmap -permstat 输出(报告为版本 24.76-b04),它报告了以下总计:

total = 5190 76930 1031431696 N/A alive=1, dead=5189 N/A

应该是条目数,类 使用此信息,用于元数据和活动信息的字节数。

现在,我想知道为什么它会报告 1031431696 bytes,当我用 -XX:MaxPermSize=256m 启动我的 VM 时只差一个千兆字节。有人可以阐明这个数字是如何计算的吗?

不知道它是否相关,但这是使用 Rhino,其中 ~3k 个条目是 DefiningClassLoaders。

我稍微看了看 jmap -permstat 实现的代码。使用的字节数是基于 classloader 加载的不同类型数据(方法、字段、接口等)的大小的估计值。

为加载的 class 计算大小的顶级方法是 sun.jvm.hotspot.tools.PermStat.computeSize:

private long computeSize(InstanceKlass k) {
  long size = 0L;

  // the InstanceKlass object itself
  size += k.getObjectSize();

  // Constant pool
  ConstantPool cp = k.getConstants();
  size += cp.getObjectSize();
  size += objectSize(cp.getCache());
  size += objectSize(cp.getTags());

  // Interfaces
  size += arraySize(k.getLocalInterfaces());
  size += arraySize(k.getTransitiveInterfaces());

  // Inner classes
  size += objectSize(k.getInnerClasses());

  // Fields
  size += objectSize(k.getFields());

  // Methods
  ObjArray methods = k.getMethods();
  int nmethods = (int) methods.getLength();
  if (nmethods != 0L) {
     size += methods.getObjectSize();
     for (int i = 0; i < nmethods; ++i) {
        Method m = (Method) methods.getObjAt(i);
        size += m.getObjectSize();
        size += objectSize(m.getConstMethod());
     }
  }

  // MethodOrdering - an int array that records the original
  // ordering of methods in the class file
  size += arraySize(k.getMethodOrdering());

  return size;
}

我的猜测是这种估计在你的情况下非常失败。如果不详细检查 JVM 版本的对象大小计算并结合应用程序中加载的 classes 的特性,很难说失败的原因。

此外,Troubleshooting Guide for Java SE 6 with HotSpot VM 提到该值是一​​个近似值。

最重要的是,对字节使用值持保留态度。