性能调优 10. JVM内存模型深度剖析与优化

1. JDK体系结构


‌‌‌  JDK: 包含JAVA运行语言,JRE运行环境,JVM虚拟机。

在这里插入图片描述


2. Java语言的跨平台特性


在这里插入图片描述

‌‌‌  不同平台JDK不同即JVM不同,所以同一JAVA代码在不同平台能生成平台对应的机器码运行,这就是跨平台。


3. JVM整体结构及内存模型


在这里插入图片描述


JVM虚拟机组成部分

在这里插入图片描述

虚拟机核心是运行时数据区

‌‌‌  1. 类装载子系统(C++):加载Class文件,丢到运行时数据区(JVM内存区)。

‌‌‌  2. 字节码执行引擎(C++),执行方法区的加载类信息的代码,修改线程运行方法内容指令时,程序计数器的存储指令的地址。

‌‌‌  3. 虚拟机每个线程,都会分配一块工作内存。一个工作内存包含,虚拟机栈,程序计数器,本地方法栈。

‌‌‌  4. 虚拟机栈和本地方法栈也成为JAVA的栈区。 栈使用都是本地内存,也就是内存条剩余物理内存


线程栈(虚拟机栈)


在这里插入图片描述

‌‌‌  1. 每个线程分配唯一的栈,私有的

‌‌‌  2. 线程运行每个方法都会分配唯一的栈帧,存放方法运行过程中的数据结构,栈帧是存放在线程栈中
‌‌‌  栈里头栈帧是后入先出,一个方法运行完栈帧就出栈,释放栈帧的数据。
‌‌‌  栈帧存放:局部变量表,动态链接,操作数栈,方法出口等。

‌‌‌  3. 栈和栈帧的大小可以设置,有默认大小。

‌‌‌  查看设置栈大小

‌‌‌  查看虚拟机栈的默认大小


‌‌‌  java -XX:+PrintFlagsFinal -version | findstr ThreadStackSize

‌‌‌  这边默认虚拟机栈VMThreadStackSize为0B。

在这里插入图片描述

‌‌‌  通过JVM启动参数来设置栈的大小。例如,使用-Xss参数可以指定每个线程的栈大小,单位可以是K、M等。例如,-Xss2M表示将线程的栈大小设置为2MB。
  
  查看设置栈帧大小


‌‌‌  java -XX:+PrintFlagsFinal -version | findstr MaxJavaStackTraceDepth

‌‌‌  这边默认栈帧大小1024B,栈帧大小是由编译器或解释器自动计算和设置的,一般不需要手动设置。

在这里插入图片描述

‌‌‌  4. 栈帧里头数据满了或者栈里头栈帧满了,会报发生栈溢出错误(StackOverflowError)。


栈帧的组成部分

局部变量表

‌‌‌  局部变量表,存储的就是某个方法运行期间,会使用或创建的变量(local variable),以数组方式存储一个存储单位称之为slot(槽)。一个方法的局部变量表长度(slot的个数,也就是数组的长度)是在编译器就已经决定了的,我们能在class文件里找到这个值

在这里插入图片描述

‌‌‌  局部变量表大概如下所示:

‌‌‌  0位置:每个方法的局部变量表,第一个位置必须是this,调用该方法的对象。

‌‌‌  方法参数列表:方法参数列表排在this后面。

‌‌‌  方法内部创建的变量:方法内部创建变量排在方法参数列表后面。譬如我们在方法里声明了一个int值,那么在局部变量表后面就会新增一个slot,存储这个int变量。但是需要注意的是,如果你只是new Object,却并没有定义变量,那么是不会增加slot的。

‌‌‌  需要注意的是,int、boolean、char、Object这种都只占一个slot,如果遇到long或者double类型的,则占用两个slot来存储。


操作数栈

‌‌‌  操作数栈,是一种栈结构。运行方法指令时,临时存放操作数据地方。类似于局部变量表,其操作数栈最大深度也是在编译期间就已经决定了,也能在class文件中找到该值

‌‌‌  JAVAP -V 命令解析一个Class文件来理解操作数栈

‌‌‌  源代码内容

在这里插入图片描述

‌‌‌  JAVAP -V 解析代码编译后Class文件的助计指令

在这里插入图片描述

‌‌‌  分析

‌‌‌  结合JVM指令表,分析其中compute方法。

‌‌‌  0. iconst_1 将int类型常量1入操作数栈。

‌‌‌  1. istore_1 将操作栈顶int类型值存入局部变量1。局部变量1相当于局部变量表数组下标1的元素。这边是局部变量a,将栈顶的常量1出栈存入a,这时a=1,局部变量都已在局部变量表中分配了一个槽

‌‌‌  2. iconst_2 将int类型常量2入栈。

‌‌‌  3. istore_2 将操作栈顶int类型值出栈存入局部变量2,这边就是赋值给b。

‌‌‌  4. iload_1 从局部变量1中装载int类型值,将a的值复制入操作栈。

‌‌‌  5. iload_2 从局部变量2中装载int类型值,将b的值复制入操作栈。

‌‌‌  6. iadd 从操作数栈顶弹出两个int类型的数值,将它们相加再入栈,这边就是a+b。结合cpu来说,该指令转成cpu指令,cpu从寄存器或内存中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值