运行时数据区域JDK1.8
这里只看JDK1.8版本。忽略1.7及之前的。

线程私有的:
- 程序计数器
- 虚拟机栈
- 本地方法栈。和虚拟机栈所发挥的作用非常相似,区别是:虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。 在 HotSpot 虚拟机中和 Java 虚拟机栈合二为一。
线程共享的:
- 堆
- 方法区
- 直接内存 (非运行时数据区的一部分)
栈、堆、方法区存储的内容
堆区:
- 存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)
- jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身 。
包括
- 新生代内存(Young Generation)
- 老生代(Old Generation)
- 字符串常量池 是 JVM 为了提升性能和减少内存消耗针对字符串(String 类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建。JDK1.7 字符串常量池和静态变量从永久代移动到了 Java 堆中。
- 注意,已经没有了永久代。在方法区里。
注意: 类级别信息,包括静态变量不再堆里,在元空间里
栈区:
- 每个线程包含一个栈区,栈中只保存基础数据类型的值和对象以及基础数据的引用
- 每个栈中的数据(基础数据类型和对象引用)都是私有的,其他栈不能访问。
- 栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。
元空间,方法区的新实现:
- 又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。
- 方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。
- 主要就是 运行时常量池。
方法区类似一种接口,永久代和元空间都是实现方式。永久代是 JDK 1.8 之前的方法区实现,JDK 1.8 及以后方法区的实现变成了元空间。
当虚拟机要使用一个类时,它需要读取并解析 Class 文件获取相关信息,再将信息存入到方法区。方法区会存储已被虚拟机加载的 类信息、字段信息、方法信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
JDK 8 版本之后 PermGen(永久代) 已被 Metaspace(元空间) 取代,元空间使用的是本地内存。
为什么要将永久代 (PermGen) 替换为元空间 (MetaSpace) 呢?
- 整个永久代有一个 JVM 本身设置的固定大小上限,无法进行调整
- 元空间里面存放的是类的元数据,这样加载多少类的元数据就不由
MaxPermSize控制了, 而由系统的实际可用空间来控制,这样能加载的类就更多了。 - 永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。
方法区里有运行时常量池。Class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有用于存放编译期生成的各种字面量(Literal)和符号引用(Symbolic Reference)的 常量池表(Constant Pool Table) 。 和static变量不一样。常量池表会在类加载后存放到方法区的运行时常量池中。
运行时常量池的功能类似于传统编程语言的符号表,尽管它包含了比典型符号表更广泛的数据。