JavaGuide
JavaGuide copied to clipboard
不同常量池在 JDK6~8 中存放的位置
根据 https://www.javatt.com/p/47643
JVM 中有三类常量池
- 静态常量池(class 文件中的常量池)
- 运行时常量池
- 字符串常量池
他们再 JDK6~8 中分别位于不同的地方
在JDK6及之前的版本: 静态常量池在Class文件中。 运行时常量池在Perm Gen区(也就是方法区)中。(所谓的方法区是在Java堆的一个逻辑部分,为了与Java堆区别开来,也称其为非堆(Non-Heap),那么Perm Gen(永久代)区也被视为方法区的一种实现。) 字符串常量池在运行时常量池中。
在JDK7版本: 静态常量池在Class文件中。 运行时常量池依然在Perm Gen区(也就是方法区)中。在JDK7版本中,永久代的转移工作就已经开始了,将譬如符号引用(Symbols)转移到了native heap;字面量(interned strings)转移到了java heap;类的静态变量(class statics)转移到了java heap。但是运行时常量池依然还存在,只是很多内容被转移,其只存着这些被转移的引用。网上流传的一些测试运行时常量池转移的方式或者代码,其实是对字符串常量池转移的测试。
在JDK8版本: 静态常量池在Class文件中。 JVM已经将运行时常量池从方法区中移了出来,在Java 堆(Heap)中开辟了一块区域存放运行时常量池。同时永久代被移除,以元空间代替。元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。其主要用于存放一些元数据。 字符串常量池存在于Java堆中。
请问这三类常量池在 JDK6~8 中分别如何对应到 JVM 的内存模型中?
有的文章把 class 常量池归入 运行时常量池,如 https://segmentfault.com/q/1010000018015110
- 运行时常量池是全局共享的,class常量池是class文件编译时确定的;
- 虚拟机加载Class之后会把class常量池中的数据放入到运行时常量池。
- String常量池位置:
- jdk1.6: 永久代(方法区)
- jdk1.7: 堆内存
- jdk1.8: 元空间
有些文章并没有区分不同类型的常量池,笼统地得出结论,如 https://blog.csdn.net/qq_42629806/article/details/99842776
- Jdk1.6及之前:有永久代,常量池1.6在方法区
- Jdk1.7:有永久代,但已经逐步“去永久代”,常量池1.7在堆
- Jdk1.8及之后:无永久代,常量池1.8在元空间
赞!老哥。加深了我对常量池的理解。
老哥我有点疑问:
周志明,深入理解JAVA虚拟机,第三版,77页
当Oracle收购BEA获得了JRockit的所有权后,准备把JRockit中的优秀功能,譬如Java Mission Control管理工具,移植到HotSpot虚拟机时,但因为两者对方法区实现的差异而面临诸多困难。考虑到HotSpot未来的发展,在JDK 6的时候HotSpot开发团队就有放弃永久代,逐步改为采用本地内存(Native Memory)来实现方法区的计划了,到了JDK 7的HotSpot,已经把原本放在永久代的字符串常量池、静态变量等移出,而到了JDK 8,终于完全废弃了永久代的概念,改用与JRockit、J9一样在本地内存中实现的元空间(Metaspace)来代替,把JDK 7中永久代还剩余的内容(主要是类型信息)全部移到元空间中。
字符串常量池的位置
- 1.6及以前,方法区的运行时常量池
- 1.7,堆
- 1.8,还是堆