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以及对后续并发隔离元数据等方面进行了优化