在討論JVM內存劃分以前,咱們先看下JAVA的執行過程 以下圖所示: 首先 java源碼文件會被編譯器編譯成.class文件,而後由類加載器加載各個類的字節碼文件,類加載完畢後,交由JVM的執行引擎來執行.在整個程序的執行過程當中JVM會用劃分出一段的空間來執行JAVA運行時的數據,這一塊就是JAVA運行時數據區.java
如上圖所示的JAVA運行是數據區也就是咱們所屬的JVM的內存劃分,下面咱們來具體看看JVM的運行時數據區究竟包含了哪些區塊?數組
** 1. 程序計數器 2. 堆 3. 棧 4. 本地方法棧 5. 方法區**多線程
如上圖所示,咱們來分析下JVM內存劃分中的每一個區域.函數
1.程序計數器性能
程序計數器說白了,就是用來保存當前線程執行程序的位置, 由於在JVM中多線程是經過輪流切換來得到CPU的執行時間,由於在線程切換後須要恢復當前線程以前執行程序的位置,因此每一個線程都須要有本身獨立的程序計數器.線程
2. JAVA虛擬機棧code
JAVA虛擬機棧就是咱們常說的棧, JAVA棧是Java方法執行的內存模型.每一個方法被執行的時候都會建立一個棧幀即每一個棧幀對應一個被調用的方法.在棧幀中包括 局部變量表,方法返回地址,指向常量池地址引用,操做數棧.以下圖所示:對象
2.1 局部變量表圖片
局部變量表 其實就是存儲函數中的局部變量(包括方法中聲明的非靜態變量以及函數的形參),對於基本類型則直接存儲,對於非基本類型即引用類型的對象,存儲的則是指向改對象的引用。
2.2 操做數棧內存
操做數棧顧名思義就是就是方法執行過程當中的表達式計算棧
2.3 方法返回地址
當一個方法執行後有兩種退出方式: 1. 執行到正常返回的字節碼指令 2. 執行過程當中遇到異常,而且該異常沒有在方法中處理.方法退出後須要返回方法被調用的位置.
2.4 常量池
運行時常量池保存的是類中固定的常量的信息的引用,其空間是從方法區域中分配.
3.JAVA堆
堆是JVM用來存儲 對象實例以及數組的內存區域,他是全部線程共享的內存區域,Java Heap是垃圾收集器管理的主要區域,所以不少時候也被稱爲「GC堆」
(1) 堆是JVM中全部線程共享的,所以在其上進行對象內存的分配均須要進行加鎖,這也致使了new對象的開銷是比較大的
(2) Sun Hotspot JVM爲了提高對象內存分配的效率,對於所建立的線程都會分配一塊獨立的空間TLAB(Thread Local Allocation Buffer),其大小由JVM根據運行的狀況計算而得,在TLAB上分配對象時不須要加鎖,所以JVM在給線程的對象分配內存時會盡可能的在TLAB上分配,在這種狀況下JVM中分配對象內存的性能和C基本是同樣高效的,但若是對象過大的話則仍然是直接使用堆空間分配
(3) TLAB僅做用於新生代的Eden Space,所以在編寫Java程序時,一般多個小的對象比大的對象分配起來更加高效。
(4) 全部新建立的Object 都將會存儲在新生代Yong Generation中。若是Young Generation的數據在一次或屢次GC後存活下來,那麼將被轉移到OldGeneration。新的Object老是建立在Eden Space。
4.方法區
方法區也是線程共享的區域 (1)在Hotspot中這塊區域對應的爲PermanetGeneration,又稱爲持久代。
(2)方法區域存放了所加載的類的信息(名稱、修飾符等)、類中的靜態變量、類中定義爲final類型的常量、類中的Field信息、類中的方法信息,當開發人員在程序中經過Class對象中的getName、isInterface等方法來獲取信息時,這些數據都來源於方法區域,同時方法區域也是全局共享的,在必定的條件下它也會被GC,當方法區域須要使用的內存超過其容許的大小時,會拋出OutOfMemory的錯誤信息。
下面咱們就來具體分析下實例化一個對象,JVM究竟發生了什麼?
以下面實例化了一個Object對象 Object obj = new Object(); 上面的這段代碼會涉及到 JAVA棧,JAVA堆,方法區這三個重要的內存區域.