分享

通过栈帧简述方法运行过程

 IT乐知 2020-05-25

Java内存分布

         每日回顾下JVM运行时内存分布,如下图:

        

         JVM内存区域主要分程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区、直接内存。其中程序计数器、Java虚拟机栈、本地方法栈属于线程隔离,即他们都有自己的线程归属,其他属于线程共享的

         今天学习的是如何执行方法内的字节码,以及执行代码时涉及的内存结构,在JVM的内存区域中与方法有关的主要是线程独有的部分,上图以及圈出,最主要的就是虚拟机栈,因为线程的Java虚拟机由栈帧组成,而每个栈帧对应一个方法

栈帧结构

         每个方法对应一个栈帧,那么想要了解方法是如何运行的就必须要了解栈帧是如何运作的,首先就要了解栈帧结构,栈帧主要分如下几个结构:

         局部变量表:用于存放参数和方法内部定义的局部变量,方法的Code属性的max_locals确定它的最大容量。

         操作数栈:先入后出栈,临时存储运行时数据,由Code属性的max_stacks设定最大值。

         动态连接:存放栈帧所属方法的引用和方法内部的一些对其他引用。

         返回地址:方法返回时需要在栈帧中保存的一些信息。

         栈帧的主要结构是以上4种,还有一些其他的信息就不再列出。

简单代码

         学习最好的方法就是通过实例,以下是一个简单的方法,代码如下图:

        

         代码比较简单,下面的内容是方法的Code的字节码,stack=2表示操作数栈深度为2,locals=6本地变量表6个,args_size=1表示有一个参数(默认参数this)。下面来分析字节码运行过程。

字节码分析

         根据字节码得出局部变量表、操作数栈等信息如下图:

        

         字节码第0行“bipush    20”表示将int型数字20压入操作栈栈顶,如下图:

        

         字节码第2行“istore_1”表示将操作栈栈顶的int型数据弹出并放到局部变量表第1位,如下图:

        

         以此类推,到11行都是相似的操作,最终结果如下图:

        

         方法最开始定义的几个变量就存储到了局部变量表中了。第13、14行分别把局部变量表第1、2位加载到操作数栈中,如下图:

        

         第15行“iadd”指令会将操作数栈顶的两个int型数据弹出并相加,将结果压入操作栈顶,如下图:

        

         第16行“iload_3”同样是把局部变量表第3项压入操作栈顶,第17行“isub”再把操作栈顶两个int数据弹出并相减,再把结果压入栈顶。

         以此内推到21行“istore   5”将栈顶的int数据存放到局部变量表5中,第23行“iload    5”则是把局部变量表第5个int数据加载到操作数栈顶,第25行“ireturn”将操作数栈顶的int数据返回。

         就是这样方法执行步骤对应对操作栈的入栈出栈,最终完成方法的执行!

总结

         每个线程都有一个私有的Java虚拟机栈,每个方法对应一个栈帧,而每个方法从调用开始到执行结束的过程,对应这线程的Java虚拟机栈中一个栈帧的入栈与出栈

         每个栈帧包含了方法执行所需要的信息,而最主要的结果是局部变量表与操作栈,方法的执行过程就是对操作栈中入栈与出栈和对局部变量表设置和获取!

Java程序员日常学习笔记,如理解有误欢迎各位交流讨论!

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多