运行时数据区-基础

为什么学习运行时数据区

  1. 熟悉jvm如何管理内存
  2. 便于排查内存泄露和内存溢出相关的问题

Java内存区域(运行时数据区域)和内存模型(JMM) 区别

  • 内存区域是指 Jvm 运行时将数据分区域存储,强调对内存空间的划分
  • 内存模型(Java Memory Model,简称 JMM )是定义了线程和主内存之间的抽象关系,即 JMM 定义了 JVM 在计算机内存(RAM)中的工作方式,如果我们要想深入了解Java并发编程,就要先理解好Java内存模型。

组成部分(jdk1.7 / jdk1.8)

  • Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域。
  • JVM规范中规定了五个部分:堆,方法区,虚拟机栈,本地方法栈,程序计数器
  • jdk7 和 jdk8 的区别
    • 虚拟机栈,本地方法栈,程序计数器 基本没变化
    • 方法区是在虚拟机规范里面被定义的,不同的虚拟机对这个定义的实现不同,在HotSpot 虚拟机中在 jdk1.7 版本之前的方法区实现叫永久代(PermGen space)(是堆的一部分),jdk1.8 之后叫做元空间(Metaspace)(是本地内存的一部分)
    • 在1.7 中被划分为 新生代,老年代,永久代, 1.8 中被划分为 新生代,老年代(默认比例1:2)
      • 新生代中进一步划分为Eden,S0(SurivorFrom),S1(SurivorTo)(默认比例 8:1:1)

在这里插入图片描述
在这里插入图片描述

  • 为什么方法区会从 堆 中移除到 堆外
    • 在 HotSpot JVM 中,永久代中用于存放类和方法的元数据以及常量池,比如Class和Method。每当一个类初次被加载的时候,它的元数据都会放到永久代中。但永久代是有大小限制的,因此如果加载的类太多,很有可能导致永久代内存溢出,即万恶的 java.lang.OutOfMemoryError: PermGen ,由于 PermGen 内存经常会溢出,因此 JVM 的开发者希望这一块内存可以更灵活地被管理,不要再经常出现这样的 OOM
    • 移除 PermGen 可以促进 HotSpot JVM 与 JRockit VM 的融合,因为 JRockit 没有永久代。
    • 根据上面的各种原因,PermGen 最终被移除,方法区移至 Metaspace,字符串常量移至 Java Heap。

从线程隔离性分类

  1. 线程共享(所有线程共享):堆,方法区
  2. 线程私有(每个线程都有一套):虚拟机栈,本地方法栈,程序计数器(与线程的生命周期一致)

与类加载的关系

在这里插入图片描述

每个区域的功能

  1. 程序计数器
    1. 记录 JVM 字节码指令地址,如果是执行 native 方法,则是未指定值(undefined)
    2. 是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成
    3. 是唯一一个在 JVM 规范中没有规定任何 OutOfMemoryError 情况的区域
  2. 虚拟机栈
    1. 每个线程在创建的时候都会创建一个虚拟机栈,其内部保存一个个的栈帧(Stack Frame),对应着一次次 Java 方法调用,是线程私有的,生命周期和线程一致。
    2. 虚拟机栈是对程序运行,方法调用的实现,每个方法执行,伴随着入栈(进栈/压栈),方法执行结束出栈
    3. 栈中可能出现的异常
      1. Java 虚拟机规范允许 Java虚拟机栈的大小是动态的或者是固定不变的
      2. 如果采用固定大小的 Java 虚拟机栈,那每个线程的 Java 虚拟机栈容量可以在线程创建的时候独立选定。如果线程请求分配的栈容量超过 Java 虚拟机栈允许的最大容量,Java 虚拟机将会抛出一个 StackOverflowError 异常
      3. 如果 Java 虚拟机栈可以动态扩展,并且在尝试扩展的时候无法申请到足够的内存,或者在创建新的线程时没有足够的内存去创建对应的虚拟机栈,那 Java 虚拟机将会抛出一个OutOfMemoryError异常
    4. 栈帧的内部结构
      1. 局部变量表(Local Variables)
      2. 操作数栈(Operand Stack)(或称为表达式栈)
      3. 动态链接(Dynamic Linking):指向运行时常量池的方法引用
      4. 方法返回地址(Return Address):方法正常退出或异常退出的地址一些附加信息
        在这里插入图片描述
  3. 本地方法栈
    1. Java 虚拟机栈用于管理 Java 方法的调用,而本地方法栈用于管理本地方法的调用
    2. 与操作系统交互
  4. 方法区
    1. 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
    2. Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做 Non-Heap(非堆),目的应该是与 Java 堆区分开来。
  5. 栈是运行时的单位,而堆是存储的单位。栈解决程序的运行问题,即程序如何执行,或者说如何处理数据。堆解决的是数据存储的问题,即数据怎么放、放在哪。

    1. 此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例以及数据都在这里分配内存。为了进行高效的垃圾回收,虚拟机把堆内存逻辑上划分成三块区域(分代的唯一理由就是优化 GC 性能)

参考文章

  • https://javaguide.cn/java/jvm/memory-area.html#%E8%BF%90%E8%A1%8C%E6%97%B6%E6%95%B0%E6%8D%AE%E5%8C%BA%E5%9F%9F
  • https://pdai.tech/md/java/jvm/java-jvm-struct.html
  • https://www.51cto.com/article/704419.html
  • https://cnblogs.com/czwbig/p/11127124.html
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值