青岛网站排名优化公司哪家好,深圳建立网站,能不能模仿百度一样做搜索引擎网站,网络营销讲师文章目录 0、运行时数据区域1、程序计数器2、JVM栈3、JVM栈--栈帧--局部变量表4、JVM栈--栈帧--操作数栈5、JVM栈--栈帧--桢数据6、栈溢出7、设置栈空间大小8、本地方法栈 0、运行时数据区域 JVM结构里#xff0c;类加载器下来#xff0c;到了运行时数据区域#xff0c;即Ja… 文章目录 0、运行时数据区域1、程序计数器2、JVM栈3、JVM栈--栈帧--局部变量表4、JVM栈--栈帧--操作数栈5、JVM栈--栈帧--桢数据6、栈溢出7、设置栈空间大小8、本地方法栈 0、运行时数据区域 JVM结构里类加载器下来到了运行时数据区域即Java程序运行时JVM管理的内存区域其又分为 栈这里可以细划分为两部分
Java虚拟机栈保存在Java中的方法本地方法栈保存的native方法c实现的那些
1、程序计数器 程序计数器Program Counter Register也叫PC寄存器每个线程会通过它来记录接下来要执行的的字节码指令的地址 举个例子 类加载阶段类加载器将字节码指令读到内存中后将原来的偏移量改为内存地址每条字节码指令都对应一个内存地址 执行完当前这一条指令后JVM的执行引擎JIT、解释器等根据程序计数器中记录的数据就拿到了接下来要执行的指令的地址。 多线程下CPU从线程A切换到线程B得知道线程B之前解释执行到哪一句指令了此时JVM的程序计数器就发挥作用了 2、JVM栈 JVM的栈采用栈的数据结构保存方法调用的基本数据先进后出其中每一个调用的方法用一个叫栈帧的东西存。 如下图流程为
main入栈
study入栈
eat入栈
eat出栈.....
sleep入栈
sleep出栈.....
study出栈.....
main出栈.....
执行结束断点打在C方法里看下IDEA中debug的栈信息点击栈里的每个方法跳到当前该方法执行在的那一行 修改程序让C程序抛出异常
public class FrameDemo{public static void main(String[] args){A();}public static void A(){System.out.println(A执行了...);B();}public static void B(){System.out.println(B执行了...);C();}public static void C(){System.out.println(C执行了...);throw new RuntimeException(测试); //异常}
}可以发现结果里也展示了异常发生时的栈信息以及每个方法具体执行到哪一行了 JVM的栈随着线程的创建而创建也随着线程的销毁而回收每个线程都有一个自己的JVM栈 3、JVM栈–栈帧–局部变量表
栈里的一个个栈帧由三部分构成 局部变量表用来存方法执行过程中的所有局部变量类被编译成字节码时局部变量表的内容就确定了 想访问一个变量自然是要在它声明定义之后所以局部变量表里的起始PC就是保存了从哪一行字节码指令开始可以访问这个变量对于变量i其值就为2。而长度字段为3即代表在2.3.4这三行里可以访问i。总之就是通过局部变量表控制可以访问每个变量的范围。 是字节码文件中的局部变量表它的作用是做安全性上的校验比如变量的生效范围。 而栈帧自己的局部变量表就是一个数组数组的每个位置叫槽slotlong和double类型占用两个槽其他类型占用一个槽。 如上图i占0号位一个槽后面long类型的j则占两个。再看字节码文件里局部变量表中的序号其实就是这个局部变量i在栈帧的局部变量表的起始槽的编号。 实例方法中的序号为0的位置存放的是this指的是当前调用方法的对象运行时会在内存中存放实例对象 的地址。 局部变量表也会存方法的形参且顺序与形参顺序一致。 一句话局部变量表中存的是实例方法的this对象、方法的形参、方法体中声明的局部变量 注意局部变量表的槽可以重复使用一旦某个局部变量不再生效当前槽就可以再次被使用。
public void test4(int k,int m){{int a 1;int b 2;}{int c 1;}int i 0;long j 1;
}执行完b2时栈帧的局部变量表长这样 再往下走字节码为
iconst_1
istore_3即把字面量1放入了3号槽复用了a变量的槽。同理往下推最终的局部变量表长这样 因此上面的代码在其栈帧的局部变量表中会占用6个槽而不是简单的111 11 1 12 9
4、JVM栈–栈帧–操作数栈
操作数栈是JVM在执行指令时用来存放中间数据的区域栈的数据结构压栈弹栈编译器就可决定操作数栈的最大深度用jclasslib验证
分析下以上源码的字节码 操作数栈的变化过程如下 最终状态
可以看到整个过程中操作数栈里最多有两个数据即操作数栈的最大深度为2此时创建栈帧时创建深度为2的操作数栈即可。
5、JVM栈–栈帧–桢数据
桢数据主要含
动态链接方法出口异常表引用
Part1动态链接当前类的字节码中引用了别的类的方法或属性要将符号引用#10转成内存地址。动态链接就保存了编号到运行时常量池的内存地址的映射关系。
Part2方法出口在栈帧的桢数据中存放了上一个方法的地址sleep方法的桢数据有study方法执行到哪一行的信息
当方法正常结束或发生异常结束时当前栈帧被弹出同时程序计数器指向上一个栈帧的下一条指令地址 Part3异常表引用存放异常捕获的范围以及这个范围发生异常后跳哪一行。 eg看异常表的第一行从起始PC 0到结束PC 2如果发生异常就跳转到第7行astore_0即把捕获的异常对象e放到局部变量表中因为catch块中大概率会用到e对象 6、栈溢出
一个线程的栈里栈帧过多占用的内存到达了分配的最大值再入栈就会StackOverflowError即栈溢出。 如下为OpenJDK8里JVM的源码不指定栈的大小时JVM创建的是一个默认大小的栈不同的操作系统里这个默认值也不同。 用无停止条件的递归来看栈溢出
public static int count 0;
//递归方法调用自己public static void recursion(){System.out.println(count);recursion();} 运行默认情况下main线程的栈里放了大约10473个栈帧 7、设置栈空间大小
添加JVM参数
-Xss栈大小单位默认是byte字节默认必须是 1024 的倍数可选k或者K(KB)、m或者M(MB)、g或者G(GB
eg:
-Xss1048576
-Xss1024K
-Xss1m
-Xss1g设置线程栈空间大小还可以用另一个参数
//注意等号-XX:ThreadStackSize1024HotSpot对栈空间的大小有范围限制Windows64位下的JDK8测试最小值为180k最大值为1024m超过这个范围即使设置了也不会生效。
//无效
-Xss1k
-Xss1025m当然局部变量过多栈帧局部变量表大、操作数栈深度大在相同大小下能存的栈帧数量也就少了。最后工作中该值建议用
-Xss256k8、本地方法栈
JVM栈中存的是Java方法的栈桢本地方法栈里存的则是native本地方法的栈帧。不过在HotSpot虚拟机中JVM栈和本地方法栈实现上使用了同一个栈空间。 如下