淺析JVM基本結構

一、Java代碼編譯和執行

程序員編寫Java程序,通過編譯器生成.class文件也就是字節碼,字節碼通過字節碼本或網絡進入Java運行平臺,Java平臺由Java虛擬機和Java應用程序接口搭建,字節碼進入虛擬機被解釋器執行。

簡單的說:Java字節碼在JRE中運行,JRE由API和JVM構成,JRE分析和執行字節碼的核心在於JVM,因此JVM是是實現Java平臺無關性,實現程序和操作系統分離的關鍵。
在這裏插入圖片描述

在這裏插入圖片描述

二、Java虛擬機的體系結構

JVM內部結構主要有三大部分:
1.類加載子系統:將.class文件加載到JVM內存
2.運行時數據區(內存):存放數據
3.執行引擎:執行運行時數據區內的數據

在這裏插入圖片描述

三、詳談運行時數據區

一個進程包含多個線程,運行時數據區包含堆,方法區,Java棧,本地方法棧和程序計數器。
其中堆和方法區時多個線程共享的,而Java棧,本地方法棧,程序計數器是每個線程獨有的。
在這裏插入圖片描述
1、堆:堆則是存放運行時產生的對象的。 和C++不同的是, Java只能在堆中存放對象, 而不能在棧上分配對象, 所有運行時產生的對象全部都存放於堆中, 包括數組。 我們知道, 在Java中, 數組也是對象。一個JVM實例中只有一個堆, 所有線程共享堆中的數據(對象)。在JVM管理的內存中堆區是最大的,也是主要的區域,在虛擬機啓動時創建。Java對象佔用的內存在堆上實現,因爲堆是線程共享的,因此在分配內存時要注意線程安全問題,通常我們採用加鎖的形式,但是這樣往往開銷會很大。
爲了提高內存回收的效率,對堆採用分代管理方式:

在這裏插入圖片描述
堆區分爲年輕代和老年代
1)年輕代(Young Generation)
對象在被創建時的首先存進年輕代,當年輕代需要回收的時候會觸發Minor GC
年輕代=Eden Space+S0+S1,S0和S1大小是相同的,這三個部分的大小都可以自定義。其中Eden區內存是連續的,分配非常快,回收也非常快。如果在執行垃圾回收之後,仍沒有足夠的內存分配,也不能再擴展,將會拋出OutOfMemoryError:Java Heap Space異常。
2)老年代(Old Generation)
老年代用於存放在年輕代中經過多次垃圾回收任然存活的對象,當老年代滿了的時候就需要對老年代進行垃圾回收,老年代的垃圾回收稱作Major GC

2、方法區:用來存放類型數據,類所有的字段和方法字節碼(靜態變量,final定義的常量和類中的field信息,方法信息)不要被名字誤導,它不只是存放方法,那麼爲什麼他是共享的,我們可以這樣理解,一個程序可能有多個線程會調用一個方法,它從共享區取可以減少內存開銷。

在Hotspot虛擬機中(一般我們使用的java都是這個虛擬機),這塊區域對應的是持久帶代,方法區上的垃圾收集很少,但是在一定情況下它也會被GC,如內存超過,就會拋出異常,它的GC主要針對常量池的內存回收和對已加載類的卸載。
在方法區中還有一部分就是運行時常量區,用於存放編譯時期生成的字面常量,符號引用和直接引用,也存放運行時產生的常量,比如String類的intern方法,作用是String維護了一個常量池,如果調用的字符“abc”已經在常量池中,則返回池中的字符串地址,否則,新建一個常量加入池中,並返回地址。

3、Java棧:Java棧是一個線程的執行區域, 它保存着一個線程中的方法的調用狀態, 也可以說, 一個Java線程的運行狀態, 都由一個Java棧來保存。

4、本地方法棧:用來存放本地方法,支持native方法的執行,存儲了每個native方法調用的狀態。本地方法棧和Java方法棧運行機制一樣,唯一的區別在於Java棧用來執行java方法,而本地方法棧用來執行native方法

5、程序計數器:程序計數器用於存放一條指令的地址, 這條指令就是虛擬機要執行的下一條指令。程序計數器和線程相關聯, 每一個線程都有一個程序計數器。由於程序計數器只是記錄當前指令地址,所以不存在內存溢出的情況,因此,程序計數器也是所有JVM內存區域中唯一一個沒有定義OutOfMemoryError的區域。

舉例說明

Object oj = new Object();

1.Object oj表示本地引用,存儲在JVM棧的本地變量表中
2.new Object()作爲對象數據存儲在堆中
3.堆中還記錄了能查詢到Object對象的類型數據(接口,方法,field,對象類型等)地址,實際的數據是存儲在方法區中的

小結

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章