JVM 内存区域介绍

JVM介绍

JVM整体结构

image text

首先我们需要知道java中都由什么组成?

对象,对象引用,类, class文件,成员变量,局部变量,静态变量,方法,基本数据类型(int…) 下面我们介绍这些组成在JVM那一块存储

方法区

方法区存储的内容:

运行时常量池, 字段和方法数据, 以及方法和构造函数的代码, 包括用于类和实例初始化以及接口初始化的特殊方法

JDK1.8以前
  • JDK1.8以前, hotspot方法区成为永久代, 方法区存在与JVM管理,
  • 设置永久代参数 -XX:MaxPermSize

这里解释一下为什么1.8以前方法区称为永久代

​ 因为HotSpot虚拟机的设计团队选择吧GC分代收集扩展到了方法区, 使用永久代的实现方式实现了方法区而已 这样Hotspot 的垃圾回收器可以像管理java堆一样管理方法区, 可以省去编写方法区的相关工作,

​ 这并不是一个好办法, 因为这样更容易出现内存溢出问题

​ java 虚拟机规范对方法区的限制很宽松, 除了和java堆一样不需要连续的内存和可以固定大小或者可以扩展外.

​ 还可以选择不实现垃圾回收, 相对而言, 垃圾回收的行为在这个区域很少出现, 但并不是跟名字一样, 永久存在了

​ 这个区域内存回收的目标, 主要是针对常量池的回收和对类型卸载, 一般来说, 这个区域的回收成绩很好, 尤其是类型的卸载, 条件相对苛刻, 但这部门的回收是有必要的, 因为在sun公司的BUG列表中, 出现低版本的hotspot 对此区未完全回收出现的内存泄露问题,

​ 根据java虚拟机规范的规定, 当方法区无法满足内存分配需求时, 将抛出OutOfMemoryError异常

JDK1.8及以后
  • JDK1.8中hotspot 将方法区的实现更改为元空间,方法区也不属于JVM内存的一块了, 移出到了本地内存, 将字符串常量池移动到了
  • 设置元空间大小的方式 -XX:MaxMetaspaceSize
运行时常量池

​ 运行时常量池也是方法区的一部分

​ Class 文件中 除了有 类的版本, 字段, 方法, 接口等描述信息, 还有常量池, 用于存放编译期生成的各种字面量和符号引用,这部分内容将**类加载**后进入方法区的运行时常量池的存放

​ 运行时常量池还可以吧字符引用翻译出来的直接引用,存放在运行时常量池中

​ 运行时常量池相对于Class文件常量池的另一个重要的特征是动态性, java语言并不要求常量池一定只有编译期才生产, 也就是说不需要提前进入Class文件的常量池, 也能进入运行时常量池,运行期也可能将新的常量放到常量池中,

jdk1.6 及以前 字符串常量池在运行时常量池中

jdk1.8及以后 字符串常量池移动到了堆中

Java 堆 是java虚拟机所管理的内存中最大的一块, java堆是被所有线程共享的一块内存, 在虚拟机启动时创建, 此内存区域唯一目的就是存放对象实例, 几乎所有的对象都在这个分配内存,

java虚拟机规范中描述

所有的对象实例以及数组都要在堆上分配内存, 但是随着JIT编译器的发展与逃逸分析技术逐渐成熟, 栈上分配, 标量替换技术将会导致一些微妙的变化, 所有的对象都分配在堆上变得没有那么绝对

java堆是垃圾回收的主要区域, 因为很多时候叫做GC堆 , 由于现在回收器都是基于分代算法, 所以java堆可以细分为:

  • Eden (年轻代)
    • From Survivor 空间
    • To Survivor 空间
  • Tenured Gen(老年代)

虚拟机栈

image text

java虚拟机栈, 每个线程都自己的虚拟机栈, 生命周期与线程一致, 每个方法在执行时都会创建一个栈帧,用于存储局部变量表,操作数栈, 动态链接, 方法返回地址, 等信息, 每一个方法调用到方法执行完毕, 对应一个栈帧入栈到出栈的过程(栈:栈先入后出),

局部变量表

是一组变量值储存空间,用于存放方法参数与编译器可知的基本数据类型,和方法内部定义的局部变量,局部变量表以变量槽为最小单位, 一个变量槽可以存放一个32位内的数据类型,boolean、byte、char、short、int、float、reference和returnAddress类型的数据,则遇到一个64位数据类型的变量(如long或double型),则会连续使用两个连续的Slot来存储,

局部变量表的数据什么时候保存的?

在 Java 程序编译为 Class 文件时,就在方法的 Code 属性的 max_locals 数据项中确定了该方法所需要分配的局部变量表的最大容量

操作数栈

虚拟机栈吧操作数栈当做工作区, 大多数指令都要从这里弹出数据, 执行运行, 然后结果压回操作数栈中,

存储的数据类型,虚拟机在操作数栈中存储数据的方式和在局部变量区中是一样的:如int、long、float、double、reference和returnType的存储。对于byte、short以及char类型的值在压入到操作数栈之前,也会被转换为int

栈中的任何一个元素都是可以任意的Java数据类型。32bit的类型占用一个栈单位深度,64bit的类型占用两个栈单位深度

动态链接

每一个栈帧内部都包含一个指向该栈帧在运行时常量池的引用, 包含这个引用的目的就是为了支持当前代码能够实现动态链接

本地方法栈

本地方法栈 与 虚拟机栈发挥的功能非常相似, 他们之间的区别不过是, 虚拟机栈服务的是java方法, 而 本地方法栈服务的是native方法

甚至有的虚拟机(Sun HotSpot)虚拟机, 直接将本地方法栈和虚拟机栈合二为一, 与虚拟栈一样, 本地方法栈区域也会抛出 StackOverflowError 和 OutOfMemoryError 异常

程序计数器

程序计数器,每个线程都有自己的程序计数器, 主要是指向下一行要执行的指令,由执行引擎来执行下一条指令, 每个线程独有就解决了在处理器(CPU)切换上下文后线程还能恢复到正确的位置, 如果线程执行 Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果执行的是 Native 方法,计数器值为Undefined。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值