JVM内存模型

了解JVM内存模型能够帮助我们优化代码,更好的利用内存空间,使程序的健壮性得以提升。
在这里插入图片描述
从大的方面一共分为两块:线程私有、线程共享。
接下来我通过一段代码来大概描述一下我们运行时的内存分部。
在这里插入图片描述
我们通过javap -c Math.class >math.txt 将class文件进行反汇编输出到math.txt 来通过jvm指令集分析。
在这里插入图片描述
我们从compute方法开始看,查看jvm指令集表得知iconst_1含义是:将int型1推送到栈顶 ,也就是在执行compute方法是会在栈中创建一个栈帧,我们知道指针是用来存储局部变量表、操作数栈,动态链接以及方法出口等信息的。

  • 在这里,我们的栈帧会为其都分配一块空间
  • int 1首先会在操作数栈入栈,在局部表量表中会存储我们的局部表量:0:this,1:a,2:b,3:c
  • 我们继续执行第二行istore_1(将栈顶元素存入第二个本地变量 ),这时int 1会从操作数栈出栈,将局部变量表1这个位置的变量赋值即a=1
  • 同理执行iconst_2、istore_2后就会给b赋值2。
  • iload_1(第二个int型局部变量进栈):将a压入操作数栈
  • iload_2(第三个int型局部变量进栈):将b压入操作数栈
  • iadd(栈顶两int型数值相加,并且结果进栈):将a、b出栈相加后的结果入栈
  • bipush 10(将一个byte型常量值推送至栈顶,这里就是10了):将10压入栈顶
  • imul(栈顶两int型数值相乘,并且结果进栈):3*10的结果入栈
  • istore_3(将栈顶int型数值存入第四个局部变量):将结果30付给c
  • iload_3(将第四个int型数值推送到栈顶):将结果出栈
  • ireturn(当前方法返回int):将结果返回。

从以上执行步骤可以看出:
我们的局部变量表用来存储局部变量,包括八大基本类型、对象引用以及返回地址。除了long、double占用两个局部变量控件Slot。局部变量表所需的内存空间在编译期确定,当进入一个方法时,方法在栈帧中所需要分配的局部变量控件是完全确定的,不可动态改变大小。
操作数栈主要用于存储临时的结果或值的,操作数栈可以存放一个jvm中定义的任意数据类型的值。在任意时刻,操作数栈都一个固定的栈深度,基本类型除了long、double占用两个深度,其它占用一个深度。
动态链接:将符号引用转换为直接引用,为了找到引用的类或方法在方法去的位置。什么是符号引用?
就是我们在一个类或方法中需要调用 其他的类的方法或本类其他的方法时,是不知道这个方法或类的具体地址的,这时候会用一些常量来表示其地址,这个就称之为符号引用。
直接引用:直接引用可以是直接指向目标的指针
方法出口:当一个方法被执行后,有两种方式退出该方法:执行引擎遇到了任意一个方法返回的字节码指令或遇到了异常,并且该异常没有在方法体内得到处理。无论采用何种退出方式,在方法退出之后,都需要返回到方法被调用的位置,程序才能继续执行。方法返回时可能需要在栈帧中保存一些信息,用来帮助恢复它的上层方法的执行状态。
本地方法栈与虚拟机栈类似,只不过是服务与native方法的。
再说一下程序计数器:是当前线程所执行字节码的行号指示器,每条线程都有一个独立的程序计数器,这类内存也称为“线程私有”的内存。正在执行java方法的话,计数器记录的是虚拟机字节码指令的地址(当前指令的地址)。如果是Natice方法,则为空。且这是一块唯一不会出现ORM的区域。
以上几块都是线程私有的,接下来说说线程间共享的。
方法区(1.8改为元空间):用于存储已经被虚拟机加载的类信息,常量,静态变量等。
堆:这个是我们接触最多的,所有对象、数组都是在这里创建的,我们通常根据对象的创建时间又划分为新生代、老年代
在这里插入图片描述
新生代主要用于存储新创建的对象,也是gc比较频繁的区域,新生代被分为三个区域,一般新创建的对象都放在Eden区,在经过一次gc后存活的对象放在会放在SurvivorFrom,再次发生gc后会将Eden、SurvivorFrom的存活对象复制到SurvivorTo,之后再gc后会将Eden、SurvivorTo对象复制到SurvivorFrom,SurvivorTo与SurvivorFrom反复交互,每次保证这两个区域有一块是空着的,就是为了保存存活对象。每发生一次gc对象的年龄就会+1,当年龄到达15(4bit,所以最大是15)后就会放入老年代,当然。去过新创建的对象在新生代放不下也会存入老年代。
gc算法之可达性分析:将 “GC Roots”对象作为起点向下搜索引用对象,如果某个对象到gc roots不可达,那么这个对象就是不可达的,但是不可达对象并不是立马被回收,它还需要经历两次可达性分析后仍是不可达,那么它将会被回收。
什么是gc roots:

  • 引用栈帧中的本地变量表的所有对象
  • 引用方法区该静态属性的所有对象
  • 引用方法区中常量的所有对象
  • 引用Native方法的所有对象
    对象的年龄、是否加锁、锁状态等信息都存储在对象头中。

今天先写这么多,后面再更新,如果理解的有误的地方欢迎大佬批评指正。。。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值