HotSpot Java虚拟机中的“方法区”“持久代”“元数据区”的关系?

Sun/Oracle JDK的HotSpot VM中,直到JDK7都有“持久代”(Permanent Generation,简称PermGen)。也称为方法区。

Oracle JDK8的HotSpot VM去掉“持久代”,以“元数据区”(Metaspace)替代之。


HotSpot Java虚拟机中的“方法区”“持久代”“元数据区”的关系?_第1张图片


1.Sun JDK6的HotSpot VM在PermGen里存的对象,按类型划分,有:


非Java对象:
instanceKlass -> Java类/接口的元数据
typeArrayKlass -> 原始类型数组的类型的元数据
objArrayKlass -> 引用类型数组的类型的元数据
*KlassKlass -> 描述*Klass对象的元数据
constantPool -> 运行时常量池,每个类有一个对应的
method -> 方法的元数据(主要存可变的部分),每个方法有一份
constMethod -> 方法元数据中不变的部分;每个方法有一份。字节码就嵌在这个对象末尾
symbol -> CONSTANT_Utf8对应的常量字符串。UTF-8编码。不是java.lang.String实例。Oracle JDK7挪到了native memory。
methodData -> 简称MDO。存有方法的profile数据,每个方法有一份


上述对象都是根正苗红的属于方法区的对象。
除*KlassKlass和symbol外,它们在Oracle JDK8都被挪到了Metaspace里。
*KlassKlass在JDK8去掉了,彻底没了。
symbol在JDK7开始就挪到了native memory,通过引用计数来管理。


Java对象:
java.lang.String及其背后的char[] -> CONSTANT_String对应的interned string,以及String.intern()对应的interned string。JDK7挪到了普通Java heap。
还有少量short[]、int[]之类的来存储元数据。这些虽然是Java对象但对Java应用不可见。这些在Oracle JDK8挪到了Java heap或者不再用Java对象(改用native的GrowableArray之类)。


这些Java对象有些可以算是属于方法区里,有些不应该算在方法区里;但它们确实都是Java对象所以必然都应该在JVM规范所说的Java heap里。


2.例如,Method area要持有“代码”(一般操作系统进程里至少主程序的代码段就在text段里),而PermGen里的对象所持有的“代码”只有Java字节码,而没包含JIT编译器后的代码;HotSpot VM里所有动态生成的代码都存在另一个空间里,CodeCache。同理,JVM要管理symbol(CONSTANT_Utf8对应物)和interned string,对应有SymbolTable和StringTable,这俩也是在native memory而不在PermGen里的。这些东西结合起来都应该算是method area的一部分。


反过来说,JDK6和之前的HotSpot VM的PermGen里确实也存有一些对象不属于method area要处理的范围。这些就是不来自Class文件的CONSTANT_String的interned string。
Interned string有两种,一种来自Class文件的常量池(CONSTANT_String),这些理应属于method area;另一种来自用户代码调用String.intern()(虽然best practice是不要在用户代码里调用这个方法),这些只应该算是普通的Java对象而不应该属于method area。


JVM规范说:
Although the method area is logically part of the heap, simple implementations may choose not to either garbage collect or compact it.
“方法区逻辑上是堆的一部分”。只看这句的话,方法区是Java heap的一部分。

但HotSpot VM把PermGen、CodeCache等都标记为“non-heap”,而只有young gen+old gen是Java heap。


转自知乎:HotSpot Java虚拟机中的“方法区”“持久代”“元数据区”的关系?

你可能感兴趣的:(jvm)