java内存布局

2022/02/03 Java 共 1265 字,约 4 分钟

运行时数据区域JDK1.8

这里只看JDK1.8版本。忽略1.7及之前的。

Java 运行时数据区域(JDK1.8 )

线程私有的:

  • 程序计数器
  • 虚拟机栈
  • 本地方法栈。和虚拟机栈所发挥的作用非常相似,区别是:虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。 在 HotSpot 虚拟机中和 Java 虚拟机栈合二为一。

线程共享的:

  • 堆
  • 方法区
  • 直接内存 (非运行时数据区的一部分)

栈、堆、方法区存储的内容

堆区:

  1. 存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)
  2. jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身 。

包括

  1. 新生代内存(Young Generation)
  2. 老生代(Old Generation)
  3. 字符串常量池 是 JVM 为了提升性能和减少内存消耗针对字符串(String 类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建。JDK1.7 字符串常量池和静态变量从永久代移动到了 Java 堆中。
  4. 注意,已经没有了永久代。在方法区里。

注意: 类级别信息,包括静态变量不再堆里,在元空间里

栈区:

  1. 每个线程包含一个栈区,栈中只保存基础数据类型的值和对象以及基础数据的引用
  2. 每个栈中的数据(基础数据类型和对象引用)都是私有的,其他栈不能访问。
  3. 栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。

元空间,方法区的新实现:

  1. 又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。
  2. 方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。
  3. 主要就是 运行时常量池。
  • 方法区类似一种接口,永久代和元空间都是实现方式。永久代是 JDK 1.8 之前的方法区实现,JDK 1.8 及以后方法区的实现变成了元空间。

  • 当虚拟机要使用一个类时,它需要读取并解析 Class 文件获取相关信息,再将信息存入到方法区。方法区会存储已被虚拟机加载的 类信息、字段信息、方法信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

  • JDK 8 版本之后 PermGen(永久代) 已被 Metaspace(元空间) 取代,元空间使用的是本地内存。

    为什么要将永久代 (PermGen) 替换为元空间 (MetaSpace) 呢?

    • 整个永久代有一个 JVM 本身设置的固定大小上限,无法进行调整
    • 元空间里面存放的是类的元数据,这样加载多少类的元数据就不由 MaxPermSize 控制了, 而由系统的实际可用空间来控制,这样能加载的类就更多了。
    • 永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。

方法区里有运行时常量池。Class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有用于存放编译期生成的各种字面量(Literal)和符号引用(Symbolic Reference)的 常量池表(Constant Pool Table) 。 和static变量不一样。常量池表会在类加载后存放到方法区的运行时常量池中。

运行时常量池的功能类似于传统编程语言的符号表,尽管它包含了比典型符号表更广泛的数据。

Search

    Table of Contents