Java 程序在 JVM 中是怎樣執(zhí)行的?(一定要看到最后)
我們都知道 Java 程序是運(yùn)行在 JVM 中的。但你可能不知道一個(gè) Java 程序在 JVM 中是怎樣執(zhí)行的。今天,就和大家來一探究竟。
首先,來看一下 JVM 的運(yùn)行時(shí)數(shù)據(jù)區(qū)域劃分:

程序計(jì)數(shù)器:字節(jié)碼執(zhí)行指示器,實(shí)時(shí)記錄字節(jié)碼執(zhí)行的行號(hào),線程私有。
虛擬機(jī)棧:也是線程私有的,它主要用來為方法提供服務(wù)。一個(gè)方法被執(zhí)行的時(shí)候,會(huì)創(chuàng)建一個(gè)棧幀,用來存放局部變量表、方法出口等信息。方法被調(diào)用時(shí)棧幀入棧,執(zhí)行結(jié)束時(shí)棧幀出棧。
本地方法棧:與虛擬機(jī)棧類似,只不過它的服務(wù)對(duì)象是本地(Native)方法。
堆:堆可謂是與程序員打交道最多的一塊區(qū)域了,也是 JVM 中最大的一塊內(nèi)存區(qū)域了。它里面主要用來存放的就是對(duì)象,垃圾回收主要就是針對(duì)這個(gè)區(qū)域。
對(duì)于程序員來說,堆和棧(虛擬機(jī)棧)是與我們關(guān)系最緊密的部分。面向?qū)ο蟮暮诵某蓡T就是對(duì)象和對(duì)象的行為(也就是方法),而堆和棧剛好是管著兩塊兒的。
讓我們回到標(biāo)題中提出的問題:Java 程序在 JVM 中是怎樣執(zhí)行的呢?先看一段很簡(jiǎn)單的代碼:
public class Example {
public static void main(String[] args) {
a();
}
public static void a() {
int a = 1;
b();
}
public static void b() {
User b = new User();
}
}代碼很簡(jiǎn)單,一個(gè)類,main() 方法調(diào)用 a() 方法,a() 方法中定義了一個(gè) int 變量 a,然后調(diào)用 b() 方法,b() 方法中 new 了一個(gè) User 對(duì)象 b。
想要弄明白這個(gè)問題,你需要一丟丟的前置知識(shí):
棧中的局部變量表用于存放 Java 的基本類型和引用類型
實(shí)例對(duì)象存放在堆內(nèi),棧中有對(duì)應(yīng)的引用類型指向該實(shí)例的內(nèi)存地址
OK,下面用一個(gè)動(dòng)畫來展示一下上面那段代碼是如何在 JVM 中運(yùn)行的:
可以結(jié)合下面的文字說明一起來看:
程序運(yùn)行
main() 方法入棧
a() 方法被調(diào)用,入棧
基本類型 a 變量在棧中被創(chuàng)建
b() 方法被調(diào)用,入棧
引用類型 b 在棧中被創(chuàng)建
User 類型的實(shí)例在堆中被創(chuàng)建
將 User 實(shí)例的內(nèi)存地址指向引用類型 b
b() 方法執(zhí)行結(jié)束,b 變量銷毀,斷開對(duì) User 實(shí)例的引用,出棧
a() 方法執(zhí)行結(jié)束,a 變量銷毀,出棧
垃圾回收將不再被引用的 User 實(shí)例回收掉
main() 方法執(zhí)行結(jié)束,出棧
程序執(zhí)行結(jié)束
打完收工。技術(shù)聊完了,下面我們聊點(diǎn)正事兒!

最后,給大家送點(diǎn)福利,關(guān)注「做個(gè)開發(fā)者」。
在Java程序在JVM中是怎樣執(zhí)行的?一文下方留言,獲贊最多的三位讀者每人送一本我的新書《Spring Boot趣味實(shí)戰(zhàn)課》。
七月三十一號(hào)開獎(jiǎng)。
另外,這次活動(dòng)是雙管齊下,公眾號(hào)和微博同步進(jìn)行。且兩個(gè)活動(dòng)可以累加,如果你都參加,那么中獎(jiǎng)幾率直接翻倍。并且支持定制簽名(如果不嫌我字丑,哈哈)。
微博上的活動(dòng)也很簡(jiǎn)單,關(guān)注「@水鏡不酷」并轉(zhuǎn)發(fā)下圖中的微博即可。
對(duì)了,如果你真的中了兩本,可以將其中一本兌換成現(xiàn)金,按照目前京東促銷價(jià)折算為 60 微信紅包(目前京東到手 57.8 元)。行了,別的不多說了大家?guī)兔D(zhuǎn)發(fā)一下吧。

掃碼了解本書詳情!
▼點(diǎn)擊閱讀原文,了解本書詳情~
