聊聊JVM的内存划分

96 阅读3分钟

image.png

一、堆

  • 定义

    • 存储对象实例的内存区域
  • 特点

    • JVM中最大的一块内存
    • 所有线程共享的
    • 垃圾回收的主要区域
  • 存储

    • 对象

    • 数组

    • 字符串常量池

      • 从Java7开始,字符串常量池从方法区移至堆中。它存储的是string对象的直接引用,而不是直接存放的对象。
    • 静态变量

      • 原本存放于方法区,但从JDK7开始被迁移到堆中
    • 线程分配缓冲区TLAB(Thread Local Allocation Buffer)

      • TLAB是虚拟机在堆内存的eden划分出来的一块专用空间,是线程专属的。在线程初始化时,虚拟机会为每个线程分配一块TLAB空间,只给当前线程使用,如果需要分配内存,就在自己的空间上分配,这样就不存在竞争的情况,可以大大提升分配效率。
      • 只是在“分配”这个动作上是线程独享的,至于在读取、垃圾回收等动作上都是线程共享的

二、虚拟机栈

  • 定义

    • 方法执行的内存模型
  • 特点

    • 不需要进行 GC
    • 线程私有的
    • 方法执行时入栈,方法执行完出栈
  • 存储

    • 栈帧(一个方法一个栈帧(FILO))

      组成

      • 局部变量表

        • 存放局部变量的内存区域
      • 操作数栈

        • 存放操作常量的内存区域
      • 动态链接

        • 将常量池中的符号引用在运行期转化为直接引用
      • 方法出口

        • 存放方法执行完位置的内存区域

三、方法区(规范)

  • java7(含)以前

    • 实现:永久代
    • 堆内部,非堆,跟年轻代和老年代是一块连续的物理内存
    • 类信息、静态变量、常量、JIT 编译后的代码、运行时常量池、字符串常量池
  • java8

    • 实现:元空间(本地内存)

      • 避免OOM异常
      • 永久代的 GC 特别难搞,严重影响 Full GC 的性能
    • 存储

      • 类的元数据

        • 包、类、方法、字段、的描述信息
      • 静态常量池

        • 定义

          • 也被称为class文件常量池,主要存放编译期生成的各种字面量和符号引用
        • 组成

          • 字面量

            • 文本字符串、final修饰的常量等
          • 符号引用

            • 以一组符号来描述所引用的目标
            • 直接指向内存中某一地址的引用称为直接引用
            • 在类被加载解析阶段会被转化成直接引用
      • 运行时常量池

        • 定义

          • 当类被加载到内存中后,JVM会将class常量池中的内容存放到运行时常量池中,与class常量池是一一对应
        • 存储

          • 存储的主要是编译期间生成的字面量、符号引用等等
        • 作用

          • 在运行期间将符号引用解析为直接引用

四、本地方法栈

  • 与虚拟机栈作用类似

  • native 方法

  • 存在的意义

    • 有时java应用需要与java外面的环境交互,比如底层操作系统,用C/C++语言
  • 不需要进行 GC

五、程序计数器

  • 记录下一个字节码执行的地址

  • 线程的位置

  • 每个线程独立拥有一个

    • 保证每个线程切换都能互不干扰
  • 生命周期与线程一致

  • 不会OOM

  • 不需要进行 GC