JVM内存模型

JVM组成部分

1. 类装载子系统

        C++实现的,将【字节码】装载到【运行时数据区(内存模型)】。

2. 字节码执行引擎

        C++实现的,执行【运行时数据区(JVM内存模型)】中【方法区】中的代码,并修改【程序计数器】的值。

3. 运行时数据区

        运行时数据区即JVM内存模型,包括以下5部分,其中“线程栈”、“程序计数器”、“本地方法栈”是每个线程独有的,而“堆”和“方法区”则是所有线程共享的。

3.1 堆

        一般new 的对象在堆中,但也会有些在栈中。堆区分成“年轻代”和“老年代”。上图中可以看出,默认情况下“年轻代”占1/3,老年代占2/3。年轻代又分成2部分,一部分占年轻代的8/10, 是 ,一般刚new的对象是放在Eden区域中一部分占年轻代的2/10的survivor区,里面分别是占1/10的s0区和s1区。

3.2 方法区(元空间)

        包含 “常量”、“静态变量”、“类信息(类元信息)”,在JDK1.8之前,方法区被叫做“永久代”/“持久代”,在1.8后改成被叫做“元空间”。

  • 方法区(元空间)用的是直接内存,即系统的运行内存,不是硬盘内存,不设置大小的话,默认初始大小是21M。详情见后面的“4. JVM内存参数设置”
  • 类信息就是类元信息,即简单说就是类的代码信息,不过是C++编写的。
  • 注意:上图虽然用 .class表示类元信息,但是这实际不是class对象!!实际是C++编写的类信息。我们程序使用的class对象还是在堆区中的。
  • 如果常量、静态变量是对象,那么这些对象是保存在堆中的,方法区保存的是对象的堆内存地址。(ps:这一特殊情况就对应上面总图中user到user的红色线条以及方法区到堆的黑色线条)
  • 对象头中有一个类型指针,指向方法区的类元信息,即对象通过这个指针找到类的代码。(ps:这特性,对应上图中堆区“Math”到方法区的“Math.class”箭头)

3.3 程序计数器

        每个【线程】独有一个程序计数器。记录当前要执行的代码所在的存储地址(这个代码是jvm指令代码),每执行完一行代码,那么【字节码执行引擎】会去修改这个线程的【程序计数器】的值。

  • 使用的场景:系统是多线程执行的,程序计数器可以恢复当前线程的代码执行

3.4 本地方法栈

        每个线程独有一份存放本地方法的栈,即“本地方法栈空间中”存放了各个线程的本地方法栈。本地方法就是非java语言的方法,常见的都是java调用c/c++底层的代码,比如Thread类的sleep方法。在java中,本地方法被native”关键词修饰,没有实现的java代码。

3.5 栈(线程)

        每个线程开始执行时,会从此区域分配一块专属的栈空间给这个线程使用。即一个线程一块栈空间,这个线程独有的栈空间内部又是一个栈结构(可以称为线程栈)。

栈桢

        一个方法被执行时,会在当前线程栈中被分配一块栈帧内存区域,分配的方式似于压入当前线程栈中,即在线程栈的栈顶分配区域。简之: 一个方法对应一块栈帧内存区域。线程栈中,每个栈帧就是这个线程栈中的一个元素,线程栈被分成多个。(可以看作 一个栈帧 = 一个方法)

一块栈帧“主要”分成如下4个部分:

  1. 局部变量表(也称为本地变量表):用来存放局部变量的,类似数组结构,每个方法有一份。方法结束后,会销毁当前方法的局部变量表。
  2. 操作数栈:栈结构,用来存放数值的,并用来进行运算操作的。即:临时的一块给运算操作存放中间结果的中转区域,主要用于保存计算过程的中间结果,存储计算过程中的临时变量值。
  3. 动态链接:在代码运行过程中,遇到一些方法引用等各个代码符号,这些符号引用会在运行到此代码符号时,就会被映射成真正的代码地址(直接引用)。这个就是动态链接过程,这个映射就是保存在对应帧栈的动态链接中。
  4. 方法出口:存放此方法(即此帧栈)被上层方法调用时,在上层方法的代码地址。用来恢复上层方法的执行。
  • 方法出口信息获取分为【正常退出】和【异常退出】。
  • 正常退出通过pc计数器的值获取,异常退出通过异常处理器表确定返回地址。
public class Math {

    public static final int initData = 666;
    public static User user = new User();

    public int compute() {  //一个方法对应一块栈帧内存区域
        int a = 1;
        int b = 2;
        int c = (a + b) * 10;
        return c;
    }

    public static void main(String[] args) {
        Math01 math = new Math01();
        math.compute();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值