JavaGuide icon indicating copy to clipboard operation
JavaGuide copied to clipboard

不同常量池在 JDK6~8 中存放的位置

Open jiabinl opened this issue 5 years ago • 3 comments

根据 https://www.javatt.com/p/47643

JVM 中有三类常量池

  1. 静态常量池(class 文件中的常量池)
  2. 运行时常量池
  3. 字符串常量池

他们再 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 的内存模型中?

jiabinl avatar Jan 05 '20 11:01 jiabinl

有的文章把 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在元空间

jiabinl avatar Jan 05 '20 11:01 jiabinl

赞!老哥。加深了我对常量池的理解。

Snailclimb avatar Jan 13 '20 01:01 Snailclimb

老哥我有点疑问:

周志明,深入理解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,还是堆

whoKnowsss avatar Apr 14 '21 15:04 whoKnowsss