还搞不定方法区、常量池、字符串常量池吗?

方法区,常量池,运行时常量池一直困扰了我很久,最近看了很多博客又再看了一遍《深入理解java虚拟机》 (第三版)

还搞不定方法区、常量池、字符串常量池吗?_第1张图片

方法区放啥?


用书本里的话就是

方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。虽然《Java虚拟机规范》中把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫作“非堆”(Non-Heap),目的是与-Java堆区 分开来。

类型信息,运行时常量池(class常量池),静态变量(static修饰)

class常量池

  • Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池表(Constant Pool Table),用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。字面量会直接存放入方法区,而符号引用会在类加载的解析阶段解析处理。字面量(Literal)和符号引用(Symbolic References)。字面量比较接近于Java语言层面的常量概念,如文本字符串、被声明为final的常量值等。而符号引用则属于编译原理方面的概念,主要包括下面几类常量:
    ·被模块导出或者开放的包(Package)
    ·类和接口的全限定名(Fully Qualified Name)
    ·字段的名称和描述符(Descriptor)
    ·方法的名称和描述符
    ·方法句柄和方法类型(Method Handle、Method Type、Invoke Dynamic)
    ·动态调用点和动态常量

类加载可以看这篇文章

运行时常量池

  • 运行时常量池是方法区的一部分,是一块内存区域,也就是class常量池被加载到内存之后的版本,不同之处是:它的字面量可以动态的添加(String#.intern()),符号引用可以被解析为直接引用。

字符串常量池

  • 在JDK6以及之前的版本,字符串常量池是在方法区中的,存放的都是字符串常量。
  • 在JDK7以及之后,就移动到堆中了。由于String.intern()发生了改变,因此String Pool中也可以存放放于堆内的字符串对象的引用。

元空间、永久代

  • 对于Java8, 元空间取消了永久代,那么是不是也就没有方法区了呢?当然不是,方法区是一个规范,规范没变,它就一直在。那么取代永久代的就是元空间。它和永久代有什么不同的?存储位置不同,永久代物理是堆的一部分,和新生代,老年代地址是连续的,而元空间属于本地内存;存储内容不同,元空间存储类的元信息、静态变量,字符串常量池并入堆中。元空间和永久代都是方法区的实现方式。

总结


注意几个点:在哪里,放什么,是什么。
class常量池:

  • 加载阶段产生,解析阶段解析处理后放入运行时常量池中
  • 放符号引用和字面量
  • 是class文件中的,一个class文件对应一个

运行时常量池:

  • 在方法区中
  • 放class常量池的内存版本

字符串常量池:

  • java7之前在方法区,之后(包含7)在堆中
  • java7之前在放字符串实例,之后(包含7)也可以存放放于堆内的字符串对象的引用

你可能感兴趣的:(JVM,jvm,java,jdk)