JVM基礎快速入門篇
Java是一門可以跨平臺的語言,但是Java本身是不可以實現跨平臺的,需要JVM實現跨平臺。javac編譯好後的class檔案,在Windows、Linux、Mac等系統上,只要該系統安裝對應的Java虛擬機器,class檔案都可以執行。達到”一次編譯,到處執行”的效果。
一、JVM是什麼?
而JVM到底是什麼呢?引用百度百科對JVM的介紹:
JVM是Java Virtual Machine(Java虛擬機器)的縮寫,JVM是一種用於計算裝置的規範,它是一個虛構出來的計算機,是通過在實際的計算機上模擬模擬各種計算機功能來實現的。
二、JVM架構知識
1.JVM主要包含類裝載器、執行時資料區(記憶體模型)、執行引擎。裡面記憶體模型有可以細分包括本地方法棧、堆、棧(執行緒)、方法區(元空間)、程式計數器。如圖所示:
1.類裝載器的作用就是負責載入class檔案,class檔案在檔案開頭有特定的檔案標示,將class檔案位元組碼內容載入到記憶體中,並將這些內容轉換成方法區中的執行時資料結構並且ClassLoader只負責class檔案的載入,至於它是否可以執行,則由執行引擎(Execution Engine)決定。類載入器又有四大類載入器:
-
啟動類載入器(Bootstrap ClassLoader):負責載入JRE核心類庫,像JRE中的rt.jar等(C/C++);
-
擴充套件類載入器(Extension ClassLoader):負責載入JRE擴充套件目錄ext中的jar包;
-
系統類載入器(Application ClassLoader):負責載入ClassPath路徑下的類包;
-
自定義的類載入器(User ClassLoader):只加載指定目錄下的jar和class,想載入其它位置的類或jar時得自行定義類載入器;
2.JVM中,物件都是在堆中分配記憶體空間的,棧只用於儲存區域性變數和臨時變數,如果是物件,只儲存引用,實際記憶體還是在堆中。棧的特點是先進後出,假設一個main方法,裡面執行了一個方法,我們是後執行的那個方法即那個執行緒,但是執行完畢後,那個執行緒是先銷燬的。每個方法在執行的同時都會建立一個棧幀,用於儲存區域性變量表(存放區域性變數的)、運算元棧(存放需要運算的資料)、動態連結、方法出口(執行完方法 回到main方法的位置)等資訊,每一個方法從呼叫直至執行完成的過程,就對應著一個棧幀在虛擬機器中入棧到出棧的過程。即一個方法對應一塊棧幀記憶體區域(存放本方法的區域性變數)。
3.方法區儲存已被虛擬機器載入的類資訊、常量(堆中的物件常量地址)、靜態變數、即時編譯器編譯後的程式碼等資料。
4.本地方法棧和棧的作用類似,但是它服務的物件是native方法,該方法得由c語言來實現。
5.程式計數器作用是當CPU多執行緒切換的時候,切回到當前執行緒的時候,回到程式計數器計數的位置,繼續執行。
三、堆記憶體的結構模型
新生代包括Eden加上2個survivor區,執行minor gc之後,大多數的物件會被回收,活著的進入s0,再次minor gc,活著的物件eden+s0->s1,再次minor gc,eden+s1->s0…這裡虛擬機器採取了分代收集的思想來管理記憶體,JVM給每個物件一個物件年齡計數器,分代年齡達到15後即物件被執行了15次minor gc後移入老年代。除此之外,s區裝不下的大物件也會直接進入老年代。
最後,老年代存的就是一些大物件和需要連續記憶體空間的物件(靜態變數、快取、執行緒池等),老年代滿了的話,會執行Full GC垃圾收集。官網對Full GC的解釋中介紹了個詞”Stop-The-World”,它會把所有的應用執行緒停掉,這時候系統會卡掉。JVM虛擬機器調優的目標就是減少full gc即減少STW。
四、垃圾回收機制
堆裡面存放new的物件和陣列,Java優於其他語言一個很重要的原因就是它能自動處理垃圾物件,也就是有垃圾回收機制(GC)。有了垃圾回收機制有幾點好處程式設計簡單,系統不容易出錯。
1.什麼是垃圾?
我們把沒有任何引用指向的物件或者一堆物件(迴圈引用)定義為垃圾。
2.系統如何定位垃圾
- 引用計數演算法-簡單且高效但是主流的Java虛擬機器裡並沒有選用引用計數演算法來管理記憶體,因為它不能解決迴圈引用的問題。
- 根可達分析演算法-將”GC Roots”物件作為起點,從這些節點開始向下搜尋引用的物件,找到的物件都標記為非垃圾物件,其餘未標記的物件都是垃圾物件。執行緒棧的本地變數、靜態變數、本地方法棧的變數等等都可以稱作GC Roots跟節點。如圖:
3.常見的垃圾回收演算法
- 複製演算法-沒有碎片 浪費記憶體空間(目前使用新生代使用的是複製演算法)
- 標記清除-位置不連續 產生記憶體碎片
- 標記壓縮-沒有碎片 效率偏低
複製演算法它將可用記憶體按容量分為大小相等的兩塊,每次只使用其中的一塊,當這一塊的記憶體用完了,就將還存活的物件複製到另外一塊上面,然後再把已使用過的記憶體空間一次清理掉。
五.常見垃圾回收器
新生代收集器:Serial、ParNew、Parallel Scavenge
老年代收集器:CMS、Serial Old、Parallel Old
整堆收集器: G1
jdk1.8 預設垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年