JVM 線(xiàn)程棧 到 函數(shù)運(yùn)行
每一個(gè)JVM線(xiàn)程來(lái)說(shuō)啟動(dòng)的時(shí)候都會(huì)創(chuàng)建一個(gè)私有的線(xiàn)程棧。一個(gè)jvm線(xiàn)程棧用來(lái)存儲(chǔ)棧幀,jvm線(xiàn)程棧和C語(yǔ)言中的棧很類(lèi)似,它負(fù)責(zé)管理局部變量、部分運(yùn)算結(jié)果,同時(shí)也參與到函數(shù)調(diào)用和函數(shù)返回的工作中。JVM規(guī)范中運(yùn)行線(xiàn)程棧的大小可以是固定的或者是動(dòng)態(tài)分配的,也可以是根據(jù)一定規(guī)則計(jì)算的。不同jvm對(duì)棧的實(shí)現(xiàn)會(huì)不同,一些可能提供給開(kāi)發(fā)人員自己控制jvm線(xiàn)程棧初始大小的方式;對(duì)于動(dòng)態(tài)分配來(lái)說(shuō)也可能提供對(duì)jvm最大和最小值的設(shè)置。
當(dāng)計(jì)算一個(gè)線(xiàn)程需要的分配的大小超出了固定值、或者設(shè)置的最大值,jvm會(huì)拋出StackOverflowError。而對(duì)于動(dòng)態(tài)分配棧來(lái)說(shuō),如果內(nèi)存不能夠提供足夠的空間來(lái)滿(mǎn)足最小值、或者需要的值JVM會(huì)拋出 OutOfMemoryError
棧幀,可以理解成一個(gè)函數(shù)執(zhí)行的環(huán)境,它管理參數(shù)、局部變量、返回值等等。
每個(gè)棧幀都包括一個(gè)管理局部變量的數(shù)組( local variables),這個(gè)數(shù)組的單元數(shù)量在編譯成字節(jié)碼的時(shí)候就能確定了。對(duì)于32-bit 一個(gè)單位能夠存放 boolean, byte, char, short, int, float, reference,returnAddress;連續(xù)兩個(gè)單位就能夠用來(lái)存儲(chǔ)long 、double。局部變量數(shù)組的下標(biāo)是從0開(kāi)始,一般而言0位置存儲(chǔ)的是this,后面接著是函數(shù)的參數(shù),再是函數(shù)中出現(xiàn)的局部變量。
每個(gè)棧幀也都包括一個(gè)(LIFO)操作棧的數(shù)據(jù)結(jié)構(gòu)(operand stack),它的大小同樣也可以在編譯的時(shí)候確定,創(chuàng)建的時(shí)候會(huì)是個(gè)空棧。舉個(gè)簡(jiǎn)單的例子,來(lái)描述它公用,對(duì)于int a+b來(lái)說(shuō),先把push a 進(jìn)入棧中,再樸實(shí) b 進(jìn)入入棧中,然后 同時(shí)pop 兩個(gè)值執(zhí)行iadd 指令,再將其加后的結(jié)果push入棧中完成指令。
除開(kāi)以上兩個(gè)關(guān)鍵的結(jié)構(gòu),每個(gè)棧幀還有常量池( run-time constant pool)、異常拋出管理等結(jié)構(gòu)。在此就不一一詳細(xì)說(shuō)來(lái)了,可以參考其他資料。
再來(lái)通過(guò)一個(gè)簡(jiǎn)單的 Demo 來(lái)說(shuō)明,一個(gè)棧幀的工作。首先,我們來(lái)看這樣的一個(gè)函數(shù):
public int comp(float number1, float number2){ int result ; if(number1 < number2) result = 1; else result = 2; return result; }
其中函數(shù)內(nèi)邏輯對(duì)應(yīng)的字節(jié)碼,如下:
0: fload_1 1: fload_2 2: fcmpg 3: ifge 11 6: iconst_1 7: istore_3 8: goto 1311: iconst_212: istore_313: iload_314: ireturn
對(duì)于這幾個(gè)字節(jié)碼指令稍微說(shuō)明下: