本講將介紹Java代碼是如何一步步運行起來的,其中涉及的編譯器,類加載器,字節碼校驗器,解釋器和JIT編譯器在整個過程當中是發揮着怎樣的做用。此外還會介紹Java程序所佔用的內存是被如何管理的:堆、棧和方法區都各自負責存儲哪些內容。最後用一小塊代碼示例來幫助理解Java程序運行時內存的變化。java
細心的讀者可能注意到了,在流程圖中還涉及到一個叫JIT的東西在步驟中沒有被解釋。那麼JIT編譯器(Just-In-Time Compiler)是若是參與進程序的執行過程當中呢?讓咱們來看如下兩個例子。緩存
固然,這只是JIT編譯器的優化手段之一,不一樣公司設計的JIT編譯器對Java程序的運行會有不一樣的優化方式。此外須要知道的是,JIT編譯器並非每次都會參與到執行過程當中來。jvm
在步驟3中咱們談到字節碼會被類加載器載入到內存,那麼載入以後JVM是如何對其進行內存管理的呢?優化
一般,在載入內存後,一個Java程序所佔用的內存會被大體分爲3塊區域:堆(heap),棧(stack)和方法區(method area)。操作系統
堆:存放new出來的東西。.net
棧:存放局部變量。線程
方法區:類型信息,字段信息,常量池(constant pool),靜態變量,方法信息等。翻譯
public final class Student extends Object implements Serializable { // 1.類信息 // 2.對象字段信息 private String name; private int score; // 3.常量池 public final int id = 0; public final String gender = "male"; // 4.靜態變量 public static int a = 0; // 5.方法信息 public int getid() { return id; } }
PC寄存器:存放將要執行的指令的地址。(由於機器的腦子不靈活,因此須要一塊專門的區域幫他記住執行到哪一步,否則它會忘記)設計
本地方法棧:與JVM棧所發揮的做用是很是類似的,其區別不過是JVM棧爲Java方法服務,而本地方法棧則是爲使用到的Native方法服務。有的虛擬機(例如Sun HotSpot虛擬機)甚至直接就把本地方法棧和虛擬機棧合二爲一。code
每一個線程擁有各自獨立的(虛擬機)棧、PC寄存器和本地方法棧。而堆和方法區則是全部線程共享的。
最後讓咱們經過一個小例子來理解Java程序執行時內存的變化。
public class Person { int id; int age; Person(int id1, int age1) { id = id1; age = age1; } public static void main(String[] args) { Person Tom = new Person(1, 25); } }
首先,在stack中申請了一塊內存,這塊內存區域名字叫Tom,此時區域裏存儲的內容爲null。
接着,調用Person的構造方法,方法的參數屬於局部變量,所以在stack中有兩塊區域分別存放id1和age1。
經過構造方法,能夠new出來一個Person的對象,這個對象連帶着其成員變量會被存放在heap中。成員變量id和age的值由存放在stack中的局部變量id1和age1賦予。
最後,將這個對象的引用值(相似於地址)傳遞給Tom,經過引用值咱們就能夠找到這個對象。
(注意:位於stack中的id1和age1會隨着構造方法調用的結束而消失,這裏爲了更好地表現全過程,所以保留在圖中。)
有問題歡迎你們在評論區留言,轉載請註明出處。