JVM007_运行时栈帧结构
運(yùn)行時棧幀結(jié)構(gòu)
執(zhí)行引擎是JVM的核心組件之一。
所有Java虛擬機(jī)的執(zhí)行引擎輸入輸出都是一致的:輸入的是字節(jié)碼二進(jìn)制流,處理過程是字節(jié)碼解析執(zhí)行的等效過程,輸出的是執(zhí)行結(jié)果。
JVM以方法作為作基本的執(zhí)行單元。“棧幀”是用于支持虛擬機(jī)進(jìn)行方法調(diào)用和方法執(zhí)行背后的數(shù)據(jù)結(jié)構(gòu)。這里的方法調(diào)用指的是確定調(diào)用那一個方法,也是JVM運(yùn)行時數(shù)據(jù)區(qū)中棧的棧元素。棧幀存儲的內(nèi)容主要有:局部變量表,操作數(shù)棧,動態(tài)連接和方法返回地址信息等。
局部變量表
局部變量表是一組變量的存儲空間。用以存儲方法參數(shù)和方法內(nèi)的局部變量。在編譯時其最大容量就被確定下來,并被寫到方法的Code屬性中的max_locals數(shù)據(jù)項(xiàng)中。
局部便量表的容量以變量槽為單位。在《JVM規(guī)范》中并沒有明確的指定一個槽占用的內(nèi)存的大小為多少,而是導(dǎo)向性的說:每個變量槽都應(yīng)該能存放一個char,boolean,short,int,byte,float,reference,returnAddress數(shù)據(jù)類型。這八個數(shù)據(jù)類型都可以用32位或者更少的物理內(nèi)存來存儲。這意味著一個變量槽所占用的物理內(nèi)存可以隨著處理器、操作系統(tǒng)或者虛擬機(jī)實(shí)現(xiàn)的不同而發(fā)生變化,只是變量槽的外觀與32位虛擬機(jī)一致。
下面的討論如果涉及到變量槽沒有特殊說明那么都是基于32位虛擬機(jī)
reference類型一般需要滿足兩個條件:
1. 通過該引用能夠直接或間接的查找到對象在Java堆中的數(shù)據(jù)存放的起始地質(zhì)或索引。
2. 通過該引用能夠直接或間接地查找到該對象對應(yīng)的數(shù)據(jù)類型在方法區(qū)中的存儲的類型信息。
returnAddress目前很少見了,用來為字節(jié)碼指令jsr,jsr_w,ret服務(wù)的,指向一條字節(jié)碼指令的地址,在一些古老的虛擬機(jī)中用來實(shí)現(xiàn)異常處理時的跳轉(zhuǎn),目前都是用異常表來處理異常的。
對于long,double這兩種64位的數(shù)據(jù)類型,需要兩個變量槽來表示。由于局部變量表是建立在線程內(nèi),且對其他線程是不可見的,所以不會存在數(shù)據(jù)競爭和線程安全問題。對于相鄰的共同存放一個64位數(shù)據(jù)結(jié)構(gòu)的變量,虛擬機(jī)不允許采取任何方式獨(dú)立訪問其中一個變量槽。若遇到就拋出異常。
當(dāng)一個方法調(diào)用時,若方法不是靜態(tài)方法,那邊變量槽第一個槽中會存放所屬對象的引用,也就是this。變量槽是可以被復(fù)用的,當(dāng)一個變量槽中的變量在字節(jié)碼執(zhí)行超過其范圍后,就可以被復(fù)用。
操作數(shù)棧
操作數(shù)棧也被稱為操作棧,是一個先入后出的棧。Java虛擬機(jī)的解釋執(zhí)行引擎被稱為”基于棧的執(zhí)行引擎“,這里的棧指的就是操作數(shù)棧。操作數(shù)棧的最大深度在Javac編譯器編譯時便確定了,并寫入到Code屬性的max_stacks數(shù)據(jù)項(xiàng)。當(dāng)操作數(shù)棧的元素是long或double的時候,那么一個數(shù)據(jù)占用兩個棧容量。Javac編譯器的數(shù)據(jù)流分析工作保證了方法在執(zhí)行的時候,任何是首操作數(shù)棧的深度都不會超過max_stacks的值。操作數(shù)棧中的數(shù)據(jù)類型必須與字節(jié)碼指令的序列嚴(yán)格匹配。
在大多數(shù)的虛擬機(jī)的實(shí)現(xiàn)中,會對棧幀作出一些優(yōu)化:讓下面棧幀的部分操作數(shù)棧與上面棧幀的局部變量部分重疊在一起,以節(jié)約空間并且在進(jìn)行方法調(diào)用時就可以直接共用一部分?jǐn)?shù)據(jù),無須額外的參數(shù)復(fù)制傳遞。
動態(tài)連接
每個棧幀都包含一個指向運(yùn)行時常量池中該棧幀所屬方法的引用,持有這個引用,就是為了支持方法調(diào)用過程中的動態(tài)連接。
動態(tài)連接是指Calss文件常量池中的不在類加載階段和不在第一次使用就轉(zhuǎn)換為直接引用的符號引用,而是在每一次運(yùn)行期間都轉(zhuǎn)換為直接引用。
方法返回地址
方法在退出的時候,需要返回到最初被調(diào)用的位置,程序才能繼續(xù)執(zhí)行,方法返回時可能需要在棧幀中保存一些信息,用來幫助恢復(fù)它上層主調(diào)方法的執(zhí)行狀態(tài)。一般來說法方法正常推出時,主調(diào)方法的PC計(jì)數(shù)器的值可以作為方法返回地址。而方法異常退出時,返回地址是通過異常處理表來確定的,棧幀中不會保存這部分信息。
關(guān)于退出,即推出方法的方式,可以分為“正常調(diào)用完成”和”異常調(diào)用完成“。正常調(diào)用完成指的時執(zhí)行引擎遇到一個方法返回的字節(jié)碼指令,退出方法。這里的方法字節(jié)碼返回指令決定了方法返回是否有返回值傳遞給上層的方法調(diào)用者。異常調(diào)用完成指的是方法在執(zhí)行過程中遇到異常(JVM內(nèi)部產(chǎn)生的、代碼中athrow指令禪寺的),只要在本方法的異常表中沒有匹配的異常處理器,就會導(dǎo)致方法退出。
方法的退出等同于當(dāng)前棧幀的出棧,所以可能存在的操作有:1.恢復(fù)上層方法的局部變量表和操作數(shù)棧 2若有返回值,將返回值壓入到調(diào)用者棧幀的操作數(shù)棧中 3調(diào)整PC計(jì)數(shù)器的值以指向方法調(diào)用指令后面的一條指令等。
附加信息
一些《JVM規(guī)范》中沒有描述的信息,例如與調(diào)試、性能收集有關(guān)的信息。
—
ubuntu系統(tǒng)弄得,不知道為什么格式不對
總結(jié)
以上是生活随笔為你收集整理的JVM007_运行时栈帧结构的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基本类型理解巩固及补码原理总结
- 下一篇: account表里有什么 银行_模拟一个