1. 程式人生 > >JVM和Android的記憶體機制

JVM和Android的記憶體機制

JVM

  • 記憶體管理
  • 垃圾回收
  • 類載入
  • 虛擬機器效能監控和優化

記憶體管理

  • 正常認為的記憶體區域包括:堆、棧,這種分法比較粗糙
  • JVM較為詳細地將記憶體劃分為若干個不同的資料區

    • 程式計數器:當前執行緒所執行的位元組碼的行號指示器,就是記錄正在執行的虛擬機器位元組碼指令的行數
    • java虛擬機器棧:我們所謂的“棧”,描述的是java方法執行的記憶體模型,一個方法對應一個棧幀,儲存區域性變量表等,一個方法的生命週期對應一個棧幀的進棧和彈棧
    • 本地方法棧:類似於虛擬機器棧,區別就是本地方法棧為虛擬機器使用的Native方法服務
    • java堆:所有的物件例項以及陣列都要在堆上分配;堆可以再進行細分為新生代和老年代
    • 方法區:用於儲存已被虛擬機器載入的類資訊、常量、靜態變數等資料,相對於java堆,方法區又叫做永久區;其中有一部分是執行時常量池,用於儲存編譯期生成的各種字面量和符號引用

垃圾回收

  • 垃圾回收器會回收不再存活的物件,但是有沒有想過回收器怎麼判斷該物件是否存活
  • 早期的JVM中有一個計數演算法,當有一個地方引用這個物件的時候,計數器加一,當引用失效的時候,計數器減一,任何時刻計數器為0時的物件都不能再被使用,但是現在主流的JVM裡面都沒有使用這個演算法,因為它很難解決物件之間的相互呼叫的問題
  • 判斷物件是否存活,使用可達性分析演算法,基本思路:通過一系列稱為“GC Roots”的物件作為起始點,從這些節點開始向下搜尋,將引用鏈作為其向下走的路徑,,當一個物件沒有任何引用鏈相連的時候,就說明這個物件是可回收的。

垃圾收集演算法

  • 標記-清除演算法:先標記在清除,不足:效率問題;空間問題
  • 複製演算法:將記憶體分為大小相等的兩部分,,每次只使用其中一部分,當這一部分用完,將其存活的物件複製到另一塊上面,再將使用過的記憶體一次性清除掉,這樣會提高效率;
  • 標記-整理演算法:當物件存活率較高的時候,使用複製演算法效率將變低,先標記在整理,標記後將所有存活的物件都向一端移動,最後一次清理邊界以外的物件
  • 分代收集演算法:java堆中分為新生代和老年代,再根據不同區域的特點採用不同的清理演算法,新生代中每次都有大批的物件死去,就選用複製演算法,老年代中物件存活率較高,就可以使用標記-清除,標記-整理的演算法

垃圾收集器

  • Serial收集器:這是一個單執行緒的收集器,最重要的是它在進行垃圾回收的過程中,其他工作的執行緒必須暫停,直到它收集結束。(stop the world)
  • ParNew收集器:Serial收集器的多執行緒版本
  • Parallel Scavenge 收集器:新生代收集器,使用複製演算法的收集器,又是並行的多執行緒收集器
  • Serial Old收集器:Serial收集器的老年代版本,也是單執行緒收集器
  • Parallel Old收集器:Parallel Scavenge 收集器的老年代版本,使用多執行緒和“標記-整理”演算法
  • CMS收集器:一種以獲取最短回收停頓時間為目標的收集器
  • G1收集器:最新收集器,JDK1.7中採用的收集器,是一款面向服務端應用的垃圾回收器,具有下面特點:
    • 並行和併發
    • 分代收集
    • 空間整合
    • 可預測的停頓

類載入

類從被載入到虛擬機器記憶體中開始,直到卸載出記憶體為止,它的整個生命週期包括了:載入、驗證、準備、解析、初始化、使用和解除安裝 這七個階段,其中驗證、準備和解析這三個部分統稱為連線(linking)

  1. 載入
    • 使用類載入器完成,生成位元組碼檔案,使用類載入器的時候,會有一個雙親委派模型
  2. 驗證
    • 檔案格式驗證
    • 元資料驗證
    • 位元組碼驗證
    • 符號引用驗證
    • 驗證對於類載入機制而言,並不是必要的階段,如果所執行的程式碼是確保安全的
  3. 準備
    • 為類的靜態變數分配記憶體和將其初始化為預設值,這些記憶體都將在方法區中進行分配。
  4. 解析
    • 虛擬機器將常量池中的符號引用替換為直接引用的過程
    • 符號引用:一組符號來描述引用的物件
    • 直接引用:能夠直接指向目標的指標,相對偏移量或是一個能間接定位到目標的控制代碼
  5. 初始化
    • 初始化是類載入的最後一步,開始真正的執行類中定義的java程式程式碼。
    • 初始化階段是執行類構造器()方法的過程。這個方法是由編譯器自動收集類中的所有變數的賦值動作和靜態語句塊中(static{}中的語句合併產生的)
  6. 使用
  7. 解除安裝

雙親委派模型

  • 類載入分類:啟動類載入器、擴充套件類載入器、應用程式類載入器
  • 雙親委派模型的工作過程:一個類載入器收到類載入的請求,它首先不會自己嘗試載入這個類,而是把這個請求委派給父類載入器完成,每個層次的類載入器都是這樣,因此所有的載入請求都會傳遞到啟動類載入器中,只有父載入器反饋自己無法完成這個載入請求時,子載入器才會嘗試自己去載入。

虛擬機器效能監控與優化

效能監控

  • JDK的視覺化工具
    • JConsole:java監視與管理控制檯:可以監控記憶體、執行緒、類、CPU使用情況等4種資訊的曲線圖
    • VisualVM:多合一故障處理工具:可以做到顯示虛擬機器程序以及程序的配置;監視應用程式的CPU、GC等資訊;方法級的程式執行效能分析;離執行緒序快照

可以參考《深入淺出Java虛擬機器》