Java虛擬機器體系結構深入研究總結
工作以來,程式碼越寫越多,程式也越來越臃腫,效率越來越低,對於我這樣一個追求完美的程式設計師來說,這是絕對不被允許的,於是除了不斷優化程式結構外,記憶體優化和效能調優就成了我慣用的“伎倆”。
要對Java程式進行記憶體優化和效能調優,不瞭解虛擬機器的內部原理(或者叫規範更嚴謹一點)是肯定不行的,這裡推薦一本好書《深入Java虛擬機器(第二版)》(Bill Venners著,曹曉剛 蔣靖 譯,實際上本文正是作者閱讀本書之後,對Java虛擬機器的個人理解闡述)。當然了,瞭解Java虛擬機器的好處並不僅限於上述兩點好處。從更深一點的技術層面上看,瞭解Java虛擬機器的規範和實現,將更加有助於我們編寫高效、穩定的Java程式碼。比如,假如瞭解Java虛擬機器的記憶體模型,瞭解虛擬機器的記憶體回收機制,那麼我們就不會過分依賴它,而會在需要的時候顯式的”釋放記憶體”(Java程式碼不能顯式釋放記憶體,但是可以通過釋放物件引用告知垃圾回收器回收該物件需要被回收),以降低不必要的記憶體消耗;假如我們瞭解Java棧的工作原理,那麼我們就可以通過減少遞迴層數,減少迴圈次數來降低堆疊溢位的風險。可能對於應用開發人員來說,可能不會直接去涉及這些Java虛擬機器底層實現的工作,但是瞭解這些背景知識,或多或少,都會對我們寫的程式產生潛移默化的好的影響。
本篇文章,將簡明扼要的說明Java虛擬機器的體系結構和記憶體模型,如有用詞不妥或解釋不準確之處,請不吝指正,深感榮幸!
Java 虛擬機器體系結構
類裝載子系統
Java虛擬機器有兩種類裝載器,分別是啟動類裝載器和使用者自定義裝載器。
通類裝載子系統通過類的全限定名(包名和類名,網路裝載還包括 URL)將 Class 裝載進執行時資料區。對於每一個被裝載的型別,Java虛擬機器都會建立一個java.lang.Class類的例項來代表該型別,該例項被放在記憶體中的堆區,而裝載的型別資訊則位於方法區,這一點和所有其他物件都是一樣的。
類裝載子系統在裝載一個型別前,除了要定位和匯入對應的二進位制class檔案外,還要驗證匯入類的正確性,為類變數分配並初始化記憶體,以及解析符號引用為直接引用,這些動作嚴格按照以下順序進行:
1)裝載——查詢並裝載型別的二進位制資料;
2)連線——執行驗證,準備以及解析(可選)
3)驗證 確保被匯入型別的正確性
4)準備 為類變數分配記憶體,並將其初始化為預設值
5)解析 把型別中的符號引用轉換為直接應用
方法區
對於每一個被類裝載子系統裝載的型別,虛擬機器都會儲存下列資料到方法區:
- 型別的全限定名
- 型別超類的全限定名(java.lang.Object沒有超類)
- 型別是類型別還是介面型別
- 型別的訪問修飾符
- 任何直接超介面的全限定名有序列表
除了上述基本型別資訊,還將儲存如下資訊:
- 型別的常量池
- 欄位資訊(包括欄位名、欄位型別、欄位修飾符)
- 方法資訊(包括方法名、返回型別、引數的數量和型別、方法修飾符,如果方法不是抽象和本地的,還將儲存方法的位元組碼、運算元棧和該方法棧幀中的區域性變數區的大小和異常表)
- 常量以外的所有類變數(其實就是類的靜態變數,因為靜態變數是所有例項共享的,且與型別直接相關,所以他們是類一級的變數,作為類的成員被儲存在方法區)
一個到類ClassLoader的引用
//返回的就是剛才儲存的ClassLoader引用 String.class.getClassLoader();
一個到Class類的引用
//將返回剛才儲存的Class類的引用 String.class;
注意,方法區也是可以被垃圾回收器回收的。
堆
Java程式在執行時建立的所有類例項或陣列都放在同一個堆中,而每一個Java虛擬機器也是有一個對空間,所有執行緒共享一個堆(這就是一個多執行緒的Java程式會產生物件訪問的同步問題的原因了)。
由於每一種Java虛擬機器都有對虛擬機器規範的不同實現,所以我們可能不知道每一種Java虛擬機器在堆中是以何種形式表示物件例項的,不過我們可以通過下面這可能的實現來一窺端倪:
程式計數器
對於執行中的Java程式而言,每一個執行緒都有自己的PC(程式計數器)暫存器,它是在該執行緒啟動時建立的,大小為一個字長,用來儲存需要被執行的下一行程式碼的位置。
Java棧
每一個執行緒都有一個Java棧,以棧幀為單位儲存執行緒的執行狀態。虛擬機器對Java棧的操作有兩種:壓棧和出棧,二者都已幀為單位。棧幀儲存了傳入引數、區域性變數、中間運算結果等資料,在方法完成時被彈出,然後釋放。
看一下兩個區域性變數相加時棧幀的記憶體快照
本地方法棧
這是 Java 呼叫作業系統本地庫的地方,用來實現 JNI(Java Native Interface,Java 本地介面)
執行引擎
Java虛擬機器的核心,控制裝入 Java 位元組碼並解析;對於執行中的Java程式而言,每一個執行緒都是一個獨立的虛擬機器執行引擎的例項,從執行緒生命週期的開始到結束,他要麼在執行位元組碼,要麼在執行本地方法。
本地介面
連線了本地方法棧和作業系統庫。
注:文中所有提到”Java虛擬機器”的地方都是指”JavaEE和JavaSE平臺的Java虛擬機器規範”。
相關文章
- Java 虛擬機器之三:Java虛擬機器的記憶體結構Java虛擬機記憶體
- 理解Android虛擬機器體系結構Android虛擬機
- Java虛擬機器內部結構Java虛擬機
- 《深入理解Java虛擬機器》個人讀書總結——JAVA虛擬機器記憶體Java虛擬機記憶體
- Java虛擬機器——類檔案結構Java虛擬機
- Java虛擬機器系列之Java記憶體結構簡介Java虛擬機記憶體
- 深入Java虛擬機器之 -- 總結面試篇Java虛擬機面試
- 面試準備之java虛擬機器記憶體結構面試Java虛擬機記憶體
- Java 虛擬機器總結給面試的你(下)Java虛擬機面試
- Java 虛擬機器總結給面試的你(中)Java虛擬機面試
- Java虛擬機器總結給面試的你(上)Java虛擬機面試
- 淺析Java虛擬機器結構與機制[轉]Java虛擬機
- Java虛擬機器,類檔案結構深度解析Java虛擬機
- Java虛擬機器之Class類檔案結構Java虛擬機
- 反虛擬機器技術總結虛擬機
- JVM虛擬機器記憶體結構簡析JVM虛擬機記憶體
- Java虛擬機器詳解(二)------執行時記憶體結構Java虛擬機記憶體
- 深入理解Java虛擬機器(類檔案結構)Java虛擬機
- 深入理解Java虛擬機器 – 類檔案結構Java虛擬機
- 深入學習Java虛擬機器——類檔案結構Java虛擬機
- Java 虛擬機器之五:Java位元組碼檔案結構Java虛擬機
- 深入理解Java虛擬機器--個人總結(持續更新)Java虛擬機
- 《深入理解java虛擬機器》學習筆記1——Java記憶體結構Java虛擬機筆記記憶體
- 每日一問:你瞭解 Java 虛擬機器結構麼?Java虛擬機
- 【深入Java虛擬機器】之二:Class類檔案結構Java虛擬機
- 《深入理解java虛擬機器》學習筆記8——Tomcat類載入器體系結構Java虛擬機筆記Tomcat
- 類檔案結構——深入理解Java虛擬機器 筆記三Java虛擬機筆記
- oracle體系結構總結Oracle
- 關於Java虛擬機器執行時資料區域的總結Java虛擬機
- Dalvik虛擬機器、Java虛擬機器與ART虛擬機器虛擬機Java
- Java虛擬機器(一)結構原理與執行時資料區域Java虛擬機
- 《Java虛擬機器原理圖解》 1.1、class檔案基本組織結構Java虛擬機圖解
- 深入理解虛擬機器之類檔案結構虛擬機
- 虛擬機器雙網路卡繫結虛擬機
- java虛擬機器和Dalvik虛擬機器Java虛擬機
- Android 虛擬機器 Vs Java 虛擬機器Android虛擬機Java
- 修改VMware虛擬機器網路卡MAC地址的方法總結虛擬機Mac
- JAVA 虛擬機器可用記憶體Java虛擬機記憶體