栈帧-操作数栈,帧数据区,栈上分配

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Qgwperfect/article/details/78385421

操作数栈主要用于保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间。

操作数栈也是先进后出的数据结构。

这里写图片描述

帧数据区:

除了局部变量表和操作数栈,java栈还需要一些数据来支持常量池解析,正常方法返回和异常处理等,大部分java字节码指令需要进行常量池访问,在帧数据区中保存着访问常量池的指针,方便程序访问常量池。

当函数返回或者出现异常时,虚拟机要恢复调用者函数的栈帧,并让调用者函数继续执行下去,对异常处理,虚拟机必须有一个异常处理表,方便在发生异常的时候找到处理异常的代码,因此异常处理表也是帧数据区中重要的一部分。

这里写图片描述

表示在字节码偏移量4~16字节可能抛出任意异常,如果遇到异常,则跳转字节码偏移19处执行,当方法抛出异常时,虚拟机就会查找类似的异常表来进行相应的处理,如果无法在异常表中找到合适的处理方法,则会结束当前函数的调用,返回调用函数,并在调用函数中抛出相同的异常,并查找调用函数 的异常表进行处理。

栈上分配:

栈上分配是java虚拟机提供的一项优化技术,对于那些线程私有的对象(指不可能被其他线程访问的对象),可以将它们打散分配在栈上,而不是分配在堆上。分配在栈上的好处是可以在函数调用结束后自行销毁,而不需要垃圾回收器的介入,从而提高系统的性能。

栈上分配的一个技术基础是进行逃逸分析。逃逸分析的目的是判断对象的作用域是否有可能逃逸出函数体。如下代码显示了一个逃逸的对象:

private static User user;
public static void alloc() {
user = new User();
user.id=1;
user.name=”test”;
}

对象User user是类的成员变量,该字段有可能被任何线程访问,因此属于逃逸对象。如下代码显示了一个非逃逸的对象:

public static void alloc() {
User user = new User();
user.id=1;
user.name=”test”;
}

在上述代码中,对象User以局部变量的形式存在,并且该对象没有alloc函数返回或者出现任何形式的公开,因此,它并未发生逃逸,所以这种情况,虚拟机就有可能将User分配在栈上,而不是堆上。

只有在server模式下,才可以启用逃逸分析。参数-XX:+DoEscapeAnalysis启用逃逸分析,-XX:+EliminateAllocations开启了标量替换(默认打开),允许将对象打散分配在栈上,比如对象拥有id和name两个字段,那么这两个字段将会被视为两个独立的局部变量进行分配。

栈上分配依赖逃逸分析和标量替换的实现。

对于大量的零散小对象,栈上分配提供了一种很好的对象分配优化策略,栈上分配速度快,并且可以有效避免垃圾回收带来的负面影响,但由于和堆空间相比,栈空间较小,因此对于大对象无法也不适合在栈上分配。

猜你喜欢

转载自blog.csdn.net/Qgwperfect/article/details/78385421
今日推荐