熱修復與插件化基礎——Java與Android虛擬機

一、Java虛擬機(JVM)

1、JVM整體結構

  1. 使用javac將java文件編譯成class文件。
  2. 類加載器(ClassLoader)將class字節碼加載進JVM對應的內存中。
  3. JVM將內存分配給方法區、堆區、棧區、本地方式棧4個部分,這4個部分分別存儲字節碼不同的部分。
  4. 垃圾回收器(gc)會管理整個內存空間中的垃圾。

2、Java代碼的編譯和執行過程

下圖是Java代碼編譯的詳細流程(即,javac的執行過程),瞭解即可,一般只要知道java文件是通過javac命令編譯成class文件,再通過java命令運行的就可以了,如:

javac Hello.java
java Hello

3、類加載器

1)Java中的類加載器

2)加載流程

  • Loading:類的信息從文件中獲取並載入到JVM的內存中。
  • Verifying:檢查讀入的結構是否符合JVM規範的描述。
  • Preparing:分配一個結構用來存儲類信息。
  • Resolving:把類的常量池中的所有符號引用變成直接引用。
  • Initializing:執行靜態初始化程序,把靜態變量初始化成指定的值。

4、內存管理

java中的內存管理指的是下圖中“內存空間”部分的內存操作。

1)Java棧區:

作用:存放java方法執行時所有的數據。
組成:由棧幀組成,一個棧幀代表一個方法的執行。

Java棧幀:每個方法從調用到執行完成就對應一個棧幀在虛擬機棧中入棧到出棧。它描述了一個方法的局部變量表、棧操作數、動態鏈接、方法出口。

2)本地方法棧

與Java棧區基於一致。

作用:本地方法棧是專門爲native方法服務的。

3)方法區

存儲被虛擬機加載的類信息、常量、靜態常量、即時編譯器編譯後等數據(這些數據在程序啓動後會永遠佔據內存)。

4)堆區

作用:所有通過new創建的對象的內存都在堆中分配。
特點:是虛擬機中最大的一塊內存,是GC要回收的部分。

對於堆區,其內存結構還有些不一樣的地方,先看下圖:

簡單來說,堆區分爲新生代(Young Generation)與老年代(Old Generation),程序在創始對象時,對象會先被分配到新生代中,當新生代區內存不足時,JVM會通過一定的算法規則將新生代中的對象轉移至老年代中,當新生代與老年代都沒有足夠的內存空間時,JVM就會拋出OOM異常。

5、垃圾回收

1、垃圾收集算法

1)引用記數算法(jdk1.2之前)

在內存創建對象的同時,會爲它創建一個引用記數器,並將引用記數器加1,每次有引用引用到此對象時,記數器就會累計加1,而當其中一個引用銷燬時,記數器就會減1,當引用記數器爲0時,說明該對象已經是垃圾對象,下次gc時,對象就會被回收了。

弊端:
對象A與對象B互相引用時,這2個對象的引用記數器永遠是正數,當這2個對象都沒有被其他對象所引用時(對象不可達),會因爲它們的引用記數器不爲0導致它們不會被gc回收。

2)可達性算法(jdk1.2 +)

也稱爲根搜索算法。把程序所有的引用關係看做是一張圖(有向圖),從GC Root節點開始尋找所有的引用節點,當所有的引用節點尋找完畢之後,剩餘的節點被認爲是沒有引用的節點,即不可達的節點,就是垃圾對象。

上圖中ObjD、E、F因爲沒有路徑可達,所以是垃圾對象。

2、引用的類型

java中的引用類型有4種:強引用、軟引用、弱引用、虛引用。其中,強引用和弱引用在開發中最常用。

弱引用的創建

// 強引用
Object obj = new Object();
// 弱引用,此時obj與wf都引用了Object對象
WeakReference<Object> wf = new WeakReference<Object>(obj);
// 斷開強引用,此時只有wf引用這個Object對象
obj = null;
// 通用弱引用獲取Object對象(可能爲null)
wf.get();

在使用wf.get()時,要判斷獲取到的對象是否爲null,因爲弱引用不會阻止對象的回收。

3、垃圾回收算法

1)標記-清除算法

從根集合遍歷所有的引用,上圖中,根集合引用了A,A引用了C,B是不可達的對象引用,在掃描階段中,B會被標記爲垃圾對象,當垃圾回收機制執行時,會直接將B對象置爲空,此時內存塊中就只剩下A、C對象引用,B就被垃圾回收給回收掉了。
優點:不需要進行對象的移動,僅對不存活的對象進行處理,在存活對象比較多的情況下極爲高效。
缺點:由於標記-清除算法會直接回收掉不存活的對象,會造成內在碎片,不利於後續對象的分配

2)複製算法

從根集合開始遍歷,上圖中,遍歷到A時是可達的,就把A複製到另一塊空閒的內存中,繼續遍歷,發現B不可達,直接跳過,往後,發現C可達,就把C同樣地複製到這塊空閒內存中,等所有複製都處理完時,把原來的內存空間清空,只保留複製後的這塊內存空間。
優點:當存活對象比較少時,極爲高效,且不會有產生內存碎片。
缺點:需要一塊內存作爲交換空間來進行對象的移動。

3)標記-整理算法

從根集合開始遍歷,通過對整個內存區的掃描,將可回收對象掃描出來,上圖中,到了第二階段,就將B標記爲可回收對象,到了第三個階段,直接掃描並消除內存中被標記的對象,同時,在回收不存活對象佔用的空間時,會將內存中所有存活對象往左端空閒處移動,並更新對應的指針。

這三種算法各有優劣,JVM在處理垃圾時會整合去使用,並不是只使用其中某個算法。當內存中存活的對象比較少時,採用“複製算法”去處理垃圾對象;當內存中存活的對象比較多時,會採用“標記-整理算法”或“標記-清除算法”去處理垃圾對象。

4、觸發回收

  • Java虛擬機無法再爲新對象分配內存空間了
  • 手動調用System.gc()方法(強烈不推薦,不會馬上執行,卻會加大虛擬機壓力)
  • 低優先級的GC線程,被啓動了。

二、Android 虛擬機

1、Dalvik VM 與 JVM 的不同

  • 執行的文件不同,一個是class,一個是dex。
  • 類加載的系統與JVM區別較大。
  • 可以同時存在多個DVM,但JVM只能存在一個。
  • Dalvik是基於寄存器的,而JVM是基於棧的。

2、Dalvik VM 與 ART 的不同

  • DVM使用JIT來將字節碼轉換成機器碼,效率低。
  • ART採用了AOT預編譯技術,執行速度更快。
  • ART會佔用更多的應用安裝時間和存儲空間。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章