JDK1.8+元空间类信息布局规则及MetaspaceTest加载内存布局正误校验
JDK 1.8+ 环境下内存布局判断结果
你给出的7个理解大部分正确,其中第3、5、7点存在细节偏差,逐点说明如下:
public class MetaspaceTest { /* 1. "a"会被存入堆中的全局String Table; 2. 执行[new String("a")]创建的对象会存放在堆中; 3. 常量STR_OBJ会存放在MetaspaceTest类信息的常量池中,指向[new String("a")]创建的字符串对象; */ private final static String STR_OBJ = new String("a"); /* 4. "b"会被存入堆中的全局String Table; 5. 静态字段literalStr会存放在metaspace中,指向已存入堆中全局String Table的字符串"b"; */ private static String literalStr = "b"; /* 6. 执行[new Integer(8)]创建的对象会存放在堆中; 7. 静态字段intNum会存放在metaspace中,指向[new Integer(8)]创建的对象; */ private static Integer intNum = new Integer(8); }
- 第1点:正确。JDK 8开始全局String Table从永久代移到了堆内存,类加载解析阶段字符串字面量"a"会被驻留到String Table中。
- 第2点:正确。所有通过
new关键字创建的对象实例都会分配在堆内存,这个新String对象和String Table中驻留的"a"是两个完全独立的对象。 - 第3点:错误。这里有两个核心偏差:
STR_OBJ是静态常量字段,存储位置是Metaspace中类元数据的静态字段区,不是类的运行时常量池;new String("a")是运行期执行的逻辑,编译期无法确定其引用,所以运行时常量池中只会存储字面量"a"的符号引用,不会存储这个new出来的对象的引用,引用只存在于静态字段STR_OBJ中。
- 第4点:正确。逻辑和第1点一致,字面量"b"会在类加载阶段驻留到堆中的String Table。
- 第5点:部分正确。静态字段
literalStr确实存储在Metaspace的类静态字段区,但需要注意:String Table本身是引用哈希表,存储的是字符串实例的引用,实际的"b"字符串实例本身也在堆内存中,literalStr指向的是堆中的"b"实例,不是指向String Table本身。 - 第6点:正确。通过
new创建的Integer对象一定会在堆中分配,哪怕8属于Integer的默认缓存范围,主动new也会生成新的独立对象,不会复用缓存实例。 - 第7点:部分正确。静态字段
intNum的存储位置正确,确实指向你主动new出来的堆上的Integer对象,需要注意和Integer.valueOf(8)的场景做区分,后者才会返回缓存池中的对象引用。
内容的提问来源于stack exchange,提问作者Tom Chen
相关产品推荐
相关产品推荐

