JAVA性能優化權威指南 讀書筆記(二)


JVM概覽

HotSpot VM基本構架

    HotSpot VM主要分爲三個部分,VM運行時,JIT編譯器,內存管理器。其中詳細的關係通過閱讀其實沒有很好的理清楚,但是這並不是書本的重點我就不進行記錄了。

 早期的hotspot VM32位的,所以內存空間被限定在4G232次方個地址位空間),但是其實在運用中java堆的大小還會受限於底層的操作系統的限制。

 隨着時代和技術的發展,64hotspot VM開始產生,這個就極大的拓展了JVM可以使用的java堆的大小,但是這個也導致了一部分的性能問題,這是由於在CPU中緩存高速緩存中的空間是的一定的,而由於java面向對象的思想策略所以會有大量的對象指針,而隨着指針的大小從32位擴展到了64位,所以oops(普通對象指針)能夠在高速緩存中的存儲數量就會相應的減少,這個會導致CPU的高速緩存的命中率下降,CPU會更多的和內存進行交互這個將會導致大約8%15%的性能損失。

 在JAVA6中這個問題得到了對應的緩解,就是引入了壓縮指針,這個新的特性同時繼承了32位指針以及64位指針的優勢。壓縮指針通過對齊以及偏移量將64位指針壓縮成32位進行存儲。當然更多的CPU寄存器也能夠避免發生寄存器卸載(將寄存器的內容轉到內存中)

HotSpot VM運行時

 下面就簡單的介紹一下HotSpot VM運行時的幾個功能劃分的部分

    命令行選項JVM運行時系統解析命令行選項,並據此配置選擇什麼JIT編譯器以及選擇何種垃圾收集器等。其中一般分爲三類,標準,非標準以及非穩定。標準是在所有的JAVA虛擬機都要求實現的,非標準和非穩定都是不強制實現的。

這個命令行選項我們可以理解爲我們輸入參數解析器,一般來說一個應用的啓動將會有不少輸入參數的輸入,這個時候輸入的參數就通過命令行選項進行解析判斷並最終產生作用效果。

    VM生命週期管理:這個部分負責虛擬機的啓動和停止,在java虛擬機的啓動和停止的步驟中有大量的細節操作。

譬如在啓動的時候會:

1、解析命令行選項

2、設置對大小和JIT編譯器

3、讀取系統環境變量,類似於CLASS_PATH

4、如果命令行有-jar選項,啓動器則從指定的jar包找入口,否則從命令行輸入找入口

5、使用標準java本地接口創建第一個線程並在其中創建Hotspot VM

6、加載入口類main-class

7、通過JNI方法CallStaticVoidMethod調用main方法,並將命令行參數傳給它

    如果應用或者是main方法執行完畢,那麼就會清理所有的未處理異常。調用本的接口方法DetachCurrentThreadmain和虛擬機脫離。每次調用DetachCurrentThread的時候會導致線程數減一,所以在最終退出的時候能夠確保沒有正在執行的任務。

    VM類加載:類加載,指類名或者接口名映射到類對象的整個過程,分爲三個階段加載、鏈接、初始化。一般來說在使用反射的時候會比較大概率的引發類加載,例如Class.forName(),JVM啓動時不光會加載不少的普通類,還會加載不少核心類ObjectThread之類。事實上加載階段是Hotspot VM和特定類加載其之間相互協作的過程。

    字節碼驗證java爲了做到類型安全在啓動的時候會驗證所有的類是不是都是由java進行編譯產生的,一般分爲兩種方法類型推導以及類型檢查,一般而言小於50的使用推導,大於的使用檢查(檢查有錯會使用推導進行二次檢查)
    類數據共享:就是可以通過預先的加載文檔生成,避免每次啓動對於部分常用類的重複加載。這些類在生成了共享文檔之後,每次啓動JVM的時候直接讀文件到內存作爲數據即可,不再需要重複加載。

    解釋器:Hotspot VM解釋器是一種基於模板的解釋器,在Hotspot VMTemplateTable中存儲瞭解釋器的信息,包含了每個字節碼對應的機器代碼,每個模板描述一個字節碼。這個就描述了一個事實,就是java在運行的時候有一大部分是通過解釋執行的,並沒有和我們想象的那樣編譯執行。

這是由於一個事實,就是系統的大部分時間都是執行的一小部分重複的代碼,所以java採取的策略就是將使用頻繁的代碼編譯,其餘代碼解釋執行。

    異常處理:java代碼遇見運行異常的時候java虛擬機就會通知異常處理程序,一般是通過推展的方法,一直重複直到找到對應的異常處理器,並執行異常處理代碼。

    同步:同步機制是爲了保證交替使用的資源的安全性,JVM使用minitor來實現線程運行代碼之間的互斥,monitor對象只能被一個線程擁有,只有擁有這個對象的線程才被允許執行對象臨界區的代碼

HotSpotVM吸收了非競爭和競爭性同步操作的最新技術,極大的提高了同步的效率,通過java5中新增的偏向鎖。大多數的同步操作使用稱爲fast-path代碼的方法,由於Hotspot VM有兩個編譯器和一個解釋器,都可以產生fast-path代碼,沒有競爭時就都通過fast-path進行處理,存在競爭的時候就通過slow-path代碼實現。

    線程管理:線程管理涉及線程從創建到終止的整個生命週期,線程管理需要管理java代碼創建的線程、直接與JVM管理的本地線程以及JVM內部創建的線程。

HotSpotVMjava線程被一一映射爲對應的本地系統線程,當java線程終止的時候本地線程也被收回

JVM內部線程大概有以下幾個:

VM線程

週期任務線程

垃圾收集線程

JIT編譯器線程

信號分發線程

    C++堆管理:除了HotSpotVM內存管理器和垃圾收集器維護的java堆意外HotspotVM還是用C/C++對存儲內部對象和數據,這些類只供HotspotVM使用並不會暴露給應用。Arena及其子類是malloc之上的一層,可以快速進行內存分配。並且在JIT的編譯過程中HotSpotClientserver Jit編譯器也會使用Arena

    JAVA本地接口:java本地接口允許是使用其他語言編寫的庫進行合作操作,JNI本地方法可以用來創建檢測更新java對象、調用java方法捕獲並拋出異常。但是注意的是JNI可能會使應用失去一次編譯到處運行的特性

    致命錯誤處理:致命錯誤並不是指的代碼中拋出的錯誤,這個錯誤往往指的是一些JVM內部的錯誤,比較常見的有outofMemoryError,當出現這種錯誤的時候JVM都被迫停滯,設計者認爲讓開發者能夠診斷和修復JVM的致命錯誤的特點非常重要。

 

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