文章目錄
- 代碼的大體執行過程
- 代碼在JVM里面的詳細執行過程
- 類加載器詳解
- 運行時數據區詳解
先來看下面這一段代碼:
代碼的大體執行過程
JDK、JRE、JVM的區別和聯系;
代碼的大體執行過程如下:
從.JAVA源文件編譯生成.class字節碼文件的過程如下:
代碼在JVM里面的詳細執行過程
在JVM內部就這個樣子的:
然后,先說說類裝載子系統:
然后是運行時數據區(內存模型)的:
最后是執行引擎:
類加載器詳解
class文件的加載過程詳細的可以看我的另一篇博客,類加載器;
補充的一點是:
虛擬機規范中明確了在5中情況下會對類進行加載:
創建對象實例:new 對象的時候,會對類進行初始化(前提是這個類沒有被初始化);
通過class文件反射創建對象;
調用類的靜態屬性或靜態屬性賦值;
調用類中的靜態方法;
初始化一個類的子類的時候,在使用子類的時候,先初始化父類;
Java虛擬機啟動時被標記為啟動類的的類,比如main所在的類;
不會被加載的情況:
在同一個虛擬機中,一個類只能被加載一次,如果已經被初始化的一個類不會再被加載;
在編譯時,能確定下來的靜態變量,不會對類進行初始化;
運行時數據區詳解
從上面的運行時數據區(內存模型)的模型圖我們可以看到,堆和方法區是線程之間共享的(會發生并發安全的地方),而虛擬機棧、本地方法棧、程序計數器是線程私有的(也就是每個線程都已自己的虛擬機棧、本地方法棧和程序計數器),下面是關于內存模型中各個部分的介紹:
程序計數器(線程私有):就是一個指針,指向方法區中的方法字節碼(用來存儲下一條指令的地址,也就是馬上要執行的指令的地址),有執行引擎讀取下一條指令,是一個非常小的空間,幾乎可以忽略不計;
方法區(線程共享):類的所有字段和方法字節碼,以及一些特殊方法如:構造函數,接口代碼也在此定義,簡單說,所有定義的方法的信息都保存在該區域,靜態變量+常量+類信息(構造方法/接口定義)+運行時常量池都存在方法區中;
虛擬機棧(線程私有):Java線程執行方法的內存模型,一個線程對應一個棧,每個方法在執行的同時都會創建一個棧幀(用于存儲局部變量表,操作數棧,動態鏈接,方法出口等信息),不存在垃圾回收等問題,只要線程一結束就釋放,生命周期和線程一致;
本地方法棧(線程私有):就是存放哪些native方法的;
堆(線程共享):很大的一塊空間,用于存放對象實例,垃圾回收主要發生的地方;
棧幀中的組成部分介紹:
局部變量表:可以這么理解,局部變量表里面存放的是一個一個的小容器,用來存放數據的,比如我們開頭那段代碼中的a = 1, b = 2,在虛擬機里面不可能真給你弄出一個a、b來存放1和2,于是就用局部變量表中的這些小容器來存放,比如容器1存放1,容器2存放2,容器3存放他們的計算結果300……,當然,除了能存放基本的數據類型以外,還可以存放引用類型的對象指針;
操作數棧:每次要進行操作時(相加、相減、乘除等等),先把相關的數都放到操作數棧里面,讓后繼續相關的操作,并將操作的結果放到局部變量表中去;
動態鏈接:比如上面那個main方法運行到第二行就要進入到add()方法中去了,就是在運行的時候將符號引用轉化為直接引用;
方法出口:比如上面的代碼,add()方法運行完之后,還要將結果返回給main方法的,這個主要指的是return一類的;