Version: Next

程序计数器

Program Counter Register

每个线程都有一个程序计数器,是线程私有的

程序计数器是一块很小的内存空间,用于存储当前运行的线程所执行的字节码的行号指示器

每个运行中的线程都有一个独立的程序计数器,在方法正在访问时,该方法的程序计数器记录的是实时虚拟机字节码指令的地址;如果该方法执行的是Native方法,则程序计数器的值为Undefined

方法区

存静态变量、常量、类信息(构造方法、接口定义、方法数据、方法代码)、符号引用、运行时常量池(JDK 1.7)、字符串常量池(JDK 1.6)

  • static
  • final
  • Class
  • 字符串常量池
    • JDK1.6方法区(永久代)
    • JDK1.7堆
    • JDK1.8堆
  • 运行时常量池
    • JDK1.6方法区(永久代)
    • JDK1.7方法区(永久代)
    • JDK1.8方法区(元空间)
方法区|永久代|元空间

方法区和永久代其实是一个东西;元空间和方法区也是一个东西;JDK1.8之后元空间取代了永久代

JVM规范把方法区描述为堆得一个逻辑部分,但他却有一个别名Non-Heap(非堆),目的应该是与JVM堆区分开来。

JDK 1.6

  • 方法区是JVM规范中的一个概念,是一种理论,类似接口
  • 永久代是三大JVM之一的HotSpot虚拟机堆JVM规范中方法区的一种实现方式,是具体实现永久代用于存放字符串常量池、运行时常量池、静态变量、类信息(构造方法、接口定义、方法数据、方法代码)

JDK1.7

  • 有永久代,但已经逐步弱化永久代,字符串常量池移动到堆中,运行时常量池还在方法区(永久代)中

JDK1.8之后

  • 彻底将永久代移除出HotSpot JVM,字符串常量池在堆中,运行时常量池在元空间(Native Heap / Metaspace)
  • 元空间是方法区概念的另一种具体实现方式
  • 元空间(Metaspace)是方法区在HotSpot JVM中的实现,方法区主要用于存储类信息(构造方法、接口定义、方法数据、方法代码)、符号引用等。元空间的本质和永久代类似,都是对JVM规范中方法区的实现。
  • 元空间与永久代的最大区别在于:
    • 永久代使用Java虚拟机内存
    • 元空间使用本地内存

对于方法区的实现,为什么从永久代更换到元空间?

出于内存空间与内存利用的角度考量

  • 永久代大小有限制,如果加载的类太多,很可能导致永久代内存溢出java.lang.OutOfMemoryError:PermGen
    • 永久代调优困难,虽然可以设置永久代大小,但是很难确定一个合适的大小,影响因素过多,不如类的数量、常量的数量具体有多少
    • 永久代中的数据会随着一次full GC发生移动,比较消耗虚拟机性能
    • HotSpot JVM的每种垃圾回收器都需要特殊处理永久代中的元数据
  • 元空间使用本地内存,理论上系统可以使用的内存有多大,元空间就有多大,不会出现内存溢出
    • 实现对元空间的无缝管理
    • 可以通过-XX:MetaspaceSize-XX:MaxMetaspaceSize配置元空间大小
    • 如果Metaspace占用达到了设定的最大值,就会触发GC来收集死亡对象和类的加载器
    • 简化了full GC以及对后续并发隔离元数据等方面进行了优化