Java虚拟机——运行时数据区域

Java虚拟机运行时数据区域详解

Java虚拟机——运行时数据区域

总览

  • 线程共享,那么其数据也可以共享,但是有可能会引发线程安全问题
  • 线程不共享,一般不会引发线程安全问题,但是数据却是不共享的

image-20241025194600698

程序计数器

从上面的图中可以看到,程序计数器是线程不共享的

概念

程序计数器保存了接下来要执行的字节码指令的地址,当该字节码指令执行完成之后,程序计数器中便会存放下一个要执行的字节码指令的地址

image-20241025195134682

作用

  • 作用一:就是同概念中所讲一样,程序计数器会存放下一个要执行的字节码指令的地址
  • 作用二:针对在高并发的情况,由于cpu执行时并不是串行执行,所以需要程序计数器记录每个线程接下来将要执行的字节码指令的地址,这样才能使cpu正确执行对应的字节码指令

问题

程序计数器会出现内存溢出吗?

  • 首先要知道什么是内存溢出。程序在使用某一块内存区域时,存放数据的内存超过了虚拟机的最大内存上限。显而易见,程序计数器时不会出现内存溢出的,因为它始终存放的都是接下来要执行的字节码的指令的地址,所以不会发生内存溢出

Java虚拟机栈

概念

image-20241106141146795

例子:

  • 首先程序执行main方法,main方法的栈帧进栈
  • 接着执行study方法,study方法的栈帧进栈
  • 接着执行eat方法,eat方法的栈帧进栈,打印出“吃饭”,然后eat方法执行完毕,eat方法的栈帧出栈
  • 接着执行sleep方法,sleep方法的栈帧进栈,打印“睡觉”,然后sleep方法执行完毕,sleep方法的栈帧出栈
  • study方法执行完毕,study方法的栈帧出栈
  • main方法执行完毕,main方法的栈帧出栈,程序结束

image-20241106141343836

销毁

image-20241106142023578

栈帧的组成

image-20241106142213567

局部变量表
  • 作用

image-20241106143014409

  • 栈帧中的局部变量表

这里注意:long和double类型占用两个槽。字节码文件中的局部变量表中的序号对应栈帧中的局部变量表中变量的起始位置。

如果又声明了一个变量 int a=0; ,那么该变量对应字节码文件中的局部变量表中的序号应该为3(因为j占用两个槽)

image-20241106143240519

  • 实例方法

image-20241106143820863

image-20241106143750672

  • 思考题

以下代码的局部变量表中会占用几个槽

image-20241106143936678

一般思路:首先 this 占一个,k占一个,m占一个,a占一个,b占一个,c占一个,i占一个,j占两个,一共9个槽,这个其实是不正确的

实际上:总共占用6个槽,因为在存放局部变量时会有一个优化。为了节省空间,局部变量表中的槽是可以进行复用的,一旦某个局部变量不再生效,当前槽就可以再次被使用。

分析:首先,this 占一个,k占一个,m占一个,这个不用多说;然后a,b将存入3和4的位置;接着存c,因为a,b都没有被使用到,所以c将被存到3的位置;接着存i,由于c没有被使用到,那么i将存放到3的位置,j存放到4和5的位置。总计占用6个槽

image-20241106144422984

操作数栈

了解一下即可

image-20241106144904084

  • 案例:计算操作数栈的最大深度

image-20241106144947859

分析一下字节码执行的过程,操作数栈的最大深度就可以轻松得出

首先,iconst_0执行,将0压入操作数栈,然后执行istore_1,将0存入局部变量表的1号位置,然后执行iload_1,将局部变量表1号位置的数据加载到操作数栈中,接着执行iconst_1,将1压入操作数栈中,执行iadd,将栈顶的两个元素相加,然后再放回操作数栈中,此时操作数栈中只有一个变量1,然后执行istore_2,将栈顶元素1存入局部变量表的2号位置,return结束执行。

分析可知,在执行时,操作数栈最多容纳的元素为2,那么操作数栈的最大深度为2

帧数据
  • 动态链接

字节码指令12行表示调用System.out的静态变量,进行打印操作

image-20241106145743795

  • 方法出口

看着解释或许会有点拗口,其实意思就是(以下面这个为例),当sleep方法执行结束后,sleep方法的栈帧就会弹出虚拟机栈,接着就会执行study方法,但是程序计数器并不知道到底该执行study方法中的第几行指令,所以需要sleep方法的栈帧中存储执行下一条指令的地址,在sleep方法的栈帧将要被弹出虚拟机栈时,将该地址存入程序计数器,以便后续程序的执行。

image-20241106150037628

  • 异常表

image-20241106150542049

例子:

起始PC与结束PC,表示从哪一行字节码指令开始到哪一行字节码指令结束捕获异常,跳转PC表示,程序出现异常,将要跳转到第几行字节码指令。第七行中astore_1,表示将刚刚捕获的异常对象的引用放在局部变量表的一号位置。

image-20241106150731723

栈内存溢出
概览

由于Java虚拟机栈内存是有限的,如果虚拟机栈中存放的栈帧过于多,就会导致栈内存溢出,线程也会直接结束

image-20241106151324937

虚拟机栈内存默认大小

image-20241106151740065

设置大小

image-20241106152144548

注意
  • 有都虚拟机对栈的内存大小做了限制,如果手动设置的值不满足该范围,那么手动设置将会失效

image-20241106152356564

  • 局部变量的影响

image-20241106152510602

  • 建议

image-20241106152611764

本地方法栈

image-20241106152815668

概览

image-20241106153014849

堆内存的溢出

image-20241106153222531

内存结构

这里有可能不是太理解。used与max无需解释,还是很好理解的。total表示java虚拟机已经分配的可用堆内存,例如,一个java虚拟机max为7G,那么total可以暂时分配1G,如果不够用,可以继续分配,但是不能超过max

image-20241106153352859

注意:并不是used=total=max时,才会抛出堆内存溢出异常,实际情况往往达到该条件更早,这与虚拟机垃圾回收有关系,具体什么原因,之后可以解释一下

设置

image-20241106154523546

image-20241106154648779

  • 建议

建议将 -Xmx 与 -Xms 设置为相同的值,这样可以减少程序所使用的内存太小或者太大,java虚拟机给total缩小或者扩张的时间

方法区

概览

image-20241106160248912

元信息

image-20241106161130946

运行时常量池

image-20241106161221476

不同版本方法区的设计

image-20241106161315808

设置大小

image-20241106161437820

  • 设置建议:如果一台服务器上部署多个Java应用,由于元空间是位于操作系统维护的直接内存中,可能会导致不同应用之间因为元空间问题而导致性能有所影响,所以建议最好设置一下元空间最大大小

字符串常量池

概览

new出来的“abc”,将会被放到堆中,s1保存其地址,s2则保存字符串常量池中的地址,显然二者不相等

image-20241106162059625

intern方法

String.intern()方法,可以手动的将字符串放入字符串常量池中

讨论一个问题:

该程序应该打印出什么样的结果?

image-20241106163450303

注意:字符串“java”在类加载时会直接加载到字符串常量池中

在JDK6中,

image-20241106163532677

所以看如下图解

image-20241106163607324

显然,应该打印出来两个false

那么在JDK7及之后的版本,

image-20241106163744999

所以看如下图解

image-20241106163805548

显然,应该打印出来一个true,一个false

直接内存

概念

image-20241106164302940

创建使用直接内存

image-20241106164354317

设置直接内存的大小

image-20241106164609215

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值