阿里云二面:簡單聊聊 Java 虛擬機(jī)棧!
大家好,我是魚皮。在面試中Java虛擬機(jī)棧是常被問起的知識(shí)點(diǎn),為了讓大家了解的更多,今天我給大家分享下這篇文章。
Java 虛擬機(jī)棧(后文簡稱棧)是線程私有的,它的生命周期和線程相同,隨著線程的創(chuàng)建而創(chuàng)建,隨著線程的死亡而死亡。
棧絕對(duì)算的上是 JVM 運(yùn)行時(shí)數(shù)據(jù)區(qū)域的一個(gè)核心,除了一些 Native 方法調(diào)用是通過本地方法棧實(shí)現(xiàn)的(后面會(huì)提到),其他所有的 Java 方法調(diào)用都是通過棧來實(shí)現(xiàn)的(也需要和其他運(yùn)行時(shí)數(shù)據(jù)區(qū)域比如程序計(jì)數(shù)器配合)。
方法調(diào)用的數(shù)據(jù)需要通過棧進(jìn)行傳遞,每一次方法調(diào)用都會(huì)有一個(gè)對(duì)應(yīng)的棧幀被壓入棧中,每一個(gè)方法調(diào)用結(jié)束后,都會(huì)有一個(gè)棧幀被彈出。
棧由一個(gè)個(gè)棧幀組成,而每個(gè)棧幀中都擁有:局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法返回地址。和數(shù)據(jù)結(jié)構(gòu)上的棧類似,兩者都是先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu),只支持出棧和入棧兩種操作。

局部變量表主要存放了編譯期可知的各種數(shù)據(jù)類型(boolean、byte、char、short、int、float、long、double)、對(duì)象引用(reference 類型,它不同于對(duì)象本身,可能是一個(gè)指向?qū)ο笃鹗嫉刂返囊弥羔槪部赡苁侵赶蛞粋€(gè)代表對(duì)象的句柄或其他與此對(duì)象相關(guān)的位置)。
操作數(shù)棧主要作為方法調(diào)用的中轉(zhuǎn)站使用,用于存放方法執(zhí)行過程中產(chǎn)生的中間計(jì)算結(jié)果。另外,計(jì)算過程中產(chǎn)生的臨時(shí)變量也會(huì)放在操作數(shù)棧中。
動(dòng)態(tài)鏈接主要服務(wù)一個(gè)方法需要調(diào)用其他方法的場(chǎng)景。在 Java 源文件被編譯成字節(jié)碼文件時(shí),所有的變量和方法引用都作為符號(hào)引用(Symbilic Reference)保存在 Class 文件的常量池里。當(dāng)一個(gè)方法要調(diào)用其他方法,需要將常量池中指向方法的符號(hào)引用轉(zhuǎn)化為其在內(nèi)存地址中的直接引用。動(dòng)態(tài)鏈接的作用就是為了將符號(hào)引用轉(zhuǎn)換為調(diào)用方法的直接引用。

??臻g雖然不是無限的,但一般正常調(diào)用的情況下是不會(huì)出現(xiàn)問題的。不過,如果函數(shù)調(diào)用陷入無限循環(huán)的話,就會(huì)導(dǎo)致棧中被壓入太多棧幀而占用太多空間,導(dǎo)致??臻g過深。那么當(dāng)線程請(qǐng)求棧的深度超過當(dāng)前 Java 虛擬機(jī)棧的最大深度的時(shí)候,就拋出StackOverFlowError錯(cuò)誤。
Java 方法有兩種返回方式,一種是 return 語句正常返回,一種是拋出異常。不管哪種返回方式,都會(huì)導(dǎo)致棧幀被彈出。也就是說,棧幀隨著方法調(diào)用而創(chuàng)建,隨著方法結(jié)束而銷毀。無論方法正常完成還是異常完成都算作方法結(jié)束。
除了StackOverFlowError錯(cuò)誤之外,棧還可能會(huì)出現(xiàn)OutOfMemoryError錯(cuò)誤,這是因?yàn)槿绻麠5膬?nèi)存大小可以動(dòng)態(tài)擴(kuò)展, 如果虛擬機(jī)在動(dòng)態(tài)擴(kuò)展棧時(shí)無法申請(qǐng)到足夠的內(nèi)存空間,則拋出OutOfMemoryError異常。
簡單總結(jié)一下程序運(yùn)行中棧可能會(huì)出現(xiàn)兩種錯(cuò)誤:
StackOverFlowError:若棧的內(nèi)存大小不允許動(dòng)態(tài)擴(kuò)展,那么當(dāng)線程請(qǐng)求棧的深度超過當(dāng)前 Java 虛擬機(jī)棧的最大深度的時(shí)候,就拋出StackOverFlowError錯(cuò)誤。OutOfMemoryError:如果棧的內(nèi)存大小可以動(dòng)態(tài)擴(kuò)展, 如果虛擬機(jī)在動(dòng)態(tài)擴(kuò)展棧時(shí)無法申請(qǐng)到足夠的內(nèi)存空間,則拋出OutOfMemoryError異常。

以上就是本期分享了。
最后,歡迎加入 魚皮的編程知識(shí)星球(點(diǎn)擊了解詳情),和 8200 多名小伙伴們一起交流學(xué)習(xí),向魚皮和大廠同學(xué) 1 對(duì) 1 提問、幫你制定學(xué)習(xí)計(jì)劃不迷茫、跟著魚皮直播做項(xiàng)目(往期項(xiàng)目可無限回看)、領(lǐng)取魚皮原創(chuàng)編程學(xué)習(xí)/求職資料等。

往期推薦
