熱修復預備知識

why發表於2017-12-23

前期預備知識

dex/class

  1. class檔案結構解析
    • 什麼是class檔案?

      能夠被jvm識別,載入並執行的檔案格式

    • 如何生成一個class檔案

      • [x] 通過IDE自動幫我們build
      • [x] 手動通過javac 去生成class檔案
        PS: 如何制定jdk版本生成位元組碼檔案呢?—>javac -target 1.6 -source 1.6 HelloWorld.java
      • [x] 通過java命令去執行class檔案
        java com.example.hostfit.Test ps: 執行時根據全類名來執行的
    • class檔案的作用 記錄類檔案的所有資訊(記錄了this super 等關鍵字)

    • class檔案結構及格式(巨集觀) class檔案結構

      • 一種八位位元組的二進位制流檔案
      • 各個資料按照順序緊密排列,無間隙
      • 每個類或介面都單獨佔一個class檔案
    • class檔案弊端

      • 記憶體佔用大,不適合移動端
      • 堆疊載入模式,載入速度慢
      • 檔案IO操作多,類查詢慢
  2. dex檔案結構解析
    • 什麼是dex檔案

      被DVM虛擬機器識別,載入並執行的檔案格式

    • 如何生成dex檔案

      • [x] 通過IDE自動幫我們build生成
      • [x] 手動通過dx命令去生成dex檔案
        • javac -target 1.6 -source 1.6 Test.java 生成class檔案。ps:指定1.6 版本為了保證相容
        • dx --dex --output=Test.dex com/example/hostfit/Test.class ps: 是根據全類名來找的
      • [x] 手動執行dex檔案在手機上
        • 將dex檔案push 到手機儲存卡中 adb push Test.dex '手機路徑(例如:/sdcard)'
        • dalvikvm -cp Test.dex com.example.hostfit.Test ps: 注意全類名
    • dex檔案的作用

      記錄整個工程中所有類檔案的資訊。

    • dex檔案結構、格式的詳解 dex檔案結構

      • 一種八位位元組的二進位制流檔案
      • 各個資料按照順序緊密排列,無間隙
      • 整個應用中所有的java原始檔都放在一個dex檔案中 ps: 不考慮android 官方提供的multidex
  3. class 與 dex 檔案對比 class 與 dex異同
    • 本質上他們都是一樣的,dex檔案從class檔案演變而來
    • class檔案存在許多冗餘資訊(一個類就有一個常量池),而dex檔案會去除冗餘,並進行整合

jvm/dvm/art 三種虛擬機器

  1. java 虛擬機器結構解析

    • jvm整體結構

    jvm 結構

    • java程式碼的編譯和執行過程

      • 程式碼編譯過程 編譯流程

      • 執行過程 載入流程 1. Loadding :類的資訊從檔案中獲取並且載入到JVM記憶體中 2. Verrifying: 檢查讀入的結構是否符合JVM規範的描述 3. Preparing: 分配一個結構用來儲存類資訊 4. Resolving: 把這個類的常量池所有的符號引用改變成直接引用 5. Initializing: 執行靜態初始化程式,把靜態變數初始化指定的值

    • Java 記憶體管理

      • Java 棧區

        用來存放Java方法執行的所有資料 ps: method call-> a -> b - c;棧區由棧幀組成,一個棧幀代表一個方法的執行。

        那什麼是棧幀呢?每一個方法從呼叫到執行完成就對應一個棧幀在虛擬機器中入棧到出棧。每一個棧幀包括區域性變數表、棧運算元、動態連結、方法出口。例如(StackOverFlow異常)

        本地方法棧:和Java方法棧如出一轍,只不過本地方法棧是專門為Native方法服務的

      • 方法區

        儲存被虛擬機器載入的類資訊,常量,靜態變數,即是編譯器後等資料,用於佔據記憶體的

      • Java堆

        所有通過New建立的物件的記憶體都在堆中分配,是虛擬機器中最大的一塊記憶體,是GC 要回收的部分

        Java 堆區記憶體

        1. Young Generation : 剛剛New出來的物件
        2. Old Generation: 當Young Generation 中記憶體空間不足的時候,就會將Young Generation 中的物件按照一定的演算法、規則等存放到Old Generation, 這樣 Young Generation 就可以繼續分配記憶體,當兩者都沒有剩餘的空間的時候,就會發生OOM異常,垃圾回收器主要針對這兩塊記憶體區域,
        3. Permanent Generation: Java8 已經移除

        特點:Young Old Generation 可以動態分配,當我們的伺服器處理的是及時通訊相關服務,就可以將Young Generation記憶體區域調整大一些;當我們不需要頻繁去建立物件的時候,可以將Young Generation 記憶體區域調整小一些,這樣達到記憶體物件常駐的效果

    • Java 記憶體回收機制

      1. 垃圾回收演算法

        • 引用計數演算法

          缺點:互相循壞引用 ,兩個物件不可達,但是GC依然不會回收

        • 可達性演算法

          Java 堆區記憶體

      2. 引用型別

        強引用、弱引用、軟引用、虛引用

      3. 如何回收垃圾

        • 標記-清除演算法

          Java 堆區記憶體 優點: 記憶體塊不需要進行物件移動,存活物件比較多的時候,高效; 缺點: 容易造成記憶體碎片,不利於後續物件的分配

        • 複製演算法

          Java 堆區記憶體 優點:存活的物件比較少,比較高效 缺點:成本需要一塊記憶體作為交換空間

        • 標記-整理演算法

          Java 堆區記憶體 優點: 解決記憶體碎片問題 缺點: 成本較高一點

      4. 觸發回收機制

        • [x] Java虛擬機器無法再為新的物件分配記憶體空間
        • [ ] 手動呼叫System.gc() 強烈不推薦
        • [x] 低優先順序的GC執行緒,被Jvm 啟動了,執行GC
  2. Dalvik 與 jvm的不同

    • 執行的檔案不同 一個是dex 一個是class檔案
    • 類載入的系統(ClassLoader)與JVM的區別比較大
    • jvm 只能同時存在一個,DVM可以同時存在多個
    • DVM 是基於暫存器的(執行更快),JVM 是基於棧的
  3. ART比Dalvik有哪些優勢

    • DVM 使用的是JIT來將位元組碼轉換成機器碼(每次執行),效率低
    • ART 是採用AOT的預編譯技術(安裝的時候就將位元組碼轉換成機器碼儲存於介質中,不需要每次進行轉換),執行速度更快
    • ART 會佔用更多的應用安裝時間和儲存空間(以空間換時間)

class loader(Java Android)

類是如何載入到虛擬機器的?

  1. Java 中的ClassLoader回顧

    Java ClassLoader 具體回顧 -> java程式碼的編譯和執行過程

  2. Android中ClassLoader 作用詳解

    • Android ClassLoader的種類

      • BootsClassLoader

        用來載入Android framework層的一些dex檔案

      • PathClassLoader

        用來載入已經安裝到系統中的apk檔案中的dex檔案

      • DexClassLoader

        用來載入指定目錄中dex檔案

      • BaseDexClassLoader

        是PathClassLoader DexClassLoader 的父類

      一個App至少需要BootClassLoader 和PathClassLoader

    • Android ClassLoader 的特點

      • 雙親代理模型特點

        當前的classLoader去載入此類,如果當前此類已經被ClassLoader載入過就不再載入,直接返回; 如果未載入,便會查詢它的Parents 是否載入過此類,如果載入過 就返回parents載入過的位元組碼檔案; 如果整個繼承線的都沒有載入過此類,便會子類真正的載入,提高類載入效率。這樣就會帶來以下兩個作用

      • 類載入的共享功能 一些FrameWork層級的類 ,一旦被頂層的classLoader載入過,那麼它就會快取到記憶體裡面,以後任何地方用到,就不用重新載入了

      • 類載入的隔離功能 不同繼承路線上的ClassLoader 載入的類不是同一個類,避免開發者自己寫一程式碼偽造成系統的類庫來訪問我們系統可見成員變數。例如:系統層級的類一般初始化的時候就會載入,比如java.lang.String, 應用程式啟動之前就會被系統載入,如果在一個app裡面寫一個自定String 替換掉java.lang.String 會造成嚴重的安全問題。判斷是否是同一個類判斷,除了className packageName 另外還需要是同一個ClassLoader載入的。

    • ClassLoader 原始碼 (載入流程)

      Java ClassLoader ClassLoader loadClass 首先判斷被自己或者雙親載入過,如果未載入過,呼叫BaseDexClassLoader 的findClass,呼叫DexPathList findClass ,並且完成將dex檔案轉換成DexFile ,轉換成Elements, 遍歷資料,呼叫DexFile loadClassBinaryName - > native

  3. Android 中動態載入要點?

    • 有許多元件(Activity)類需要註冊才能使用
    • 資源動態載入複雜(註冊、相容性)
    • 程式執行的時候需要一個上下文環境

相關文章