• 认识JVM的内存模型


    从上一节了解到整个JVM大的内存区域,分为线程共享的heap(堆),MethodArea(方法区),和线程独享的 The pc Register(程序计数器)、Java Virtual Machine Stacks(Java虚拟机栈)、Native Method Stacks(本地方法栈),如下图
    image.png
    同时也大概了解到各个内存区域主要存储的数据类型,根据之前的了解,明白了作为开发者要关注的是堆、方法区和Java虚拟机栈,先从Java虚拟机栈开始

    Java虚拟机栈

    Java虚拟机栈是线程独享的一个栈结构,遵循先进后出的原则,栈中存放着一个一个栈帧,每个栈帧代表着一个方法的调用,或者说,每调用一个方法,就向该线程的虚拟机栈中压入一个栈帧,当方法执行完成就弹出,栈帧中存放着对应的方法执行的数据
    image.png

    栈帧

    如上图所示,每个栈帧中存放着以下数据

    1. 局部变量表 Array数组,存放着方法内的变量
    2. 操作数栈 栈结构,存放着操作数栈和中间计算结果,比如方法中代码int a=3,数值3就是操作数
    3. 动态链接 一种用于实现运行时动态绑定的机制,主要是指在运行时确定引用方法的实际方法体,用于实现多态和动态绑定
    4. 返回地址 当前方法执行结束后调用者的执行位置
    通过代码和反编译代码理解Java虚拟机栈和栈帧

    了解栈之后,需要明确一个事情,栈帧中局部变量表里的局部变量如果是引用类型,它实际存储的是内存地址,指向对应的堆中的对象
    如下一段代码:

    public class Person {
        public static int a = 100;
        public int b = 90;
        public static Object obj1 = new Object();
        
        public static int add(int i, int j) {
            Object obj2 = new Object();
            int k = 80;
            int result = i + j;
            return result;
        }
    
        public static void main(String[] args) {
            add(100,200);
            System.out.println("method add done");
        }
    }
    // 反编译后的指令码 只展示add方法
    public static int add(int, int);
        Code:
           0: bipush        80 	//把数值80压入操作数栈的栈顶,供后续的运算或方法调用使用
           2: istore_2		   	//将操作数栈顶的整数值存储到局部变量表索引为2的位置
           3: iload_0			//从局部变量0中装载一个int类型值到操作数栈中
           4: iload_1			//加载位于局部变量表第2个位置的int类型变量
           5: iadd				//将两个栈顶的整数相加,然后将相加的结果压入栈顶
           6: istore_3			//将栈顶的整数存储到局部变量3中
           7: iload_3			//将第3个局部变量槽中的整型值加载到操作数栈的栈顶
           8: ireturn			//当前方法将执行完毕,并将栈顶的整数作为方法的返回值返回给调用者
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    根据上面代码,画出他在虚拟机栈中的存储
    image.png
    由上图也可以看出方法区和堆有互相引用
    方法区中会存储静态变量,常量等信息,上面代码中public static Object obj1 = new Object();obj1存放在方法区中,对应的对象在堆中,就是方法区指向堆
    对象头中记录的信息包含着指向对象对应的类元数据的内存地址,即堆指向了方法区

    对象的内存布局

    一个Java对象在内存中包括三个部分:对象头、示例数据和对齐填充
    image.png

    内存模型

    根据以上信息引入Java虚拟机内存模型
    主要是堆和非堆

    堆分为Yong区和Old区

    Yong区

    Yong区又分为Eden,S0和S1,或者将S0和S1成为from和to,主要是为了垃圾回收

    Old区
    对象在内存中存储的变化
    1. 首先创建对象会分配在Eden区
    2. Eden区满,发生YongGC,扔存活的对象会放进S0,S0空间不足则直接放进Old区
    3. Eden区再次满,再次YongGC,多次YongGC使得对象年龄超过15的放进Old区或当S区中某一年龄以上的对象占用到S区一半时,将该年龄和以上的所有对象放进Old区
    4. Old区满是发生MajorGC,发生MajorGC时一般都伴随着YongGC,所以一般发生的是FullGC
    5. 当FullGC后仍无法存放时就会抛出OOM
    非堆
  • 相关阅读:
    (附源码)计算机毕业设计SSM基于的仓库管理系统
    简单网站模板1(HTML)
    利用javascript编写用户输入两个数,计算两个数字之间所以数字的和
    Win11系统开启网址默认浏览器怎么修改教学
    Spring自带的这11个工具类,真香!
    c++学习之优先级队列
    【wpf】实战 ItemsControl + 用户控件 + 绑定
    Ubuntu 24.04 LTS 安装配置 MySQL Community Server 8.4.0 LTS
    vue 2 与 vue3 获取模版引用 (ref)的区别
    Enzo CYTO-ID自噬检测试剂盒特点&作用机制
  • 原文地址:https://blog.csdn.net/hcwdd/article/details/132644225