1. 程式人生 > >深入理解Java虛擬機器總結

深入理解Java虛擬機器總結

  • 引用技術演算法:給物件新增一個引用計數器,每當有一個地方引用它時,計數器值加1;當引用失效,計數器減1;任何石刻計數器為0物件就不可使用。但無法解決物件之間相互引用的問題,如A引用B,B引用A,此時A和B的引用都為1,但是再無其他引用,實際上已經死亡卻無法回收
  • 可達性分析演算法:通過一系列的GC Roots物件作為起點,從起點開始向下搜尋,搜尋走過的路徑稱為引用鏈,當一個物件到GC Roots沒有任何引用鏈相連,則物件不可用(圖論中的,從GC Roots不可達)。可以用作GC Roots的物件:虛擬機器棧(棧幀中的本地變量表)中引用的物件,方法區中鏡頭屬性引用的物件,方法區中常量引用的物件,本地方法棧中JNI(Native方法)引用的物件。
  • 四種引用:強引用,通常我們使用的引用,類似(Object obj=new Object()),只要引用還在,垃圾收集器永遠不會回收掉被引用物件;軟引用,有用但非必須的物件,在記憶體將要發生溢位異常之前進行第二次回收(即使引用在),採用SoftReference類(SoftReference sf= new SoftReference(new Object()));弱引用,非必須物件的引用,只能生存到下一次垃圾收集器發生之前,採用WeakReference類來實現軟引用;虛引用,也稱為幽靈引用或幻影引用,無法通過虛引用來取得一個物件的例項,為一個物件設定虛引用關聯的唯一目的就是能在這個物件被收集器回收的時候收到一個系統通知,參考
    博文
  • 死亡還是生存:要真正宣告一個物件死亡,至少要經歷兩次標記過程:如果物件在進行可達性分析後沒有發現與GC Roots相連結的引用鏈,那他將會被第一次標記並且進行一次篩選,篩選的條件是次物件是否有必要執行finalize()方法,如果未過載finalize()或者已經執行過finalize()則不用再執行finalize(),稍後對執行finalize()的物件進行第二次標記,執行finalize()方法後如果物件被重新引用,則可以存活。注:虛擬機器只會觸發這個方法,但並不承諾會等待他執行結束,所以也可能在finalize()中自救失敗,而且finalize()自救只有一次機會,因為不會第二次執行finalize()
  • 回收方法區:判斷一個常量是否是廢棄常量與Java堆一致,判斷一個類是否是無用類需要滿足3個條件–該類所有的例項都已經被回收,也就是Java堆中不存在該類的任何例項;載入該類的ClassLoader已經被回收;該類對應的java.langClass物件沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法
  • 標記-清除演算法:首先標記出所有需要回收的物件,在標記完成後統一回收所有被標記的物件
  • 複製演算法:將可用記憶體按容量劃分為大小相等的兩塊,每次使用其中的一塊,當一塊的記憶體用完了,就將還存活的物件複製到另一塊上面,然後再把已使用過的記憶體空間一次清空(Eden和Survivor)
  • 標記-整理演算法:標記過程仍然與標記-清楚演算法一樣,讓所以存活物件都向一端移動,然後直接清理掉邊界意外的內容
  • 列舉根節點:使用OopMap的資料結構來存放物件的引用
  • 安全點:搶先式中斷和主動式中斷
  • 垃圾收集器:Serial–CMS/Serial Old,ParNew–CMS/Serial Old,Parallel Scavenge–Serial Old/Parrallel Old,G1
  • Serial/Serial Old:單執行緒收集器;新生代採取複製演算法,暫停所有使用者執行緒;老年代採用標記整理演算法,暫停所有使用者執行緒。虛擬機器執行在client模式下的預設新生代收集器
  • ParNew/Parallel Old:多執行緒收集器;新生代採取複製演算法,暫停所有使用者執行緒;老年代採用標記整理演算法,暫停所有使用者執行緒
  • Parallel Scavenge:新生代收集器,採用複製演算法,吞吐量優先收集器。在注重吞吐量以及CPU資源敏感的場合,都可以優先考慮Parallel Scavenge+Parallel Old
  • CMS(Concurrent Mark Sweep):一種以獲取最短回收停頓事件為目標的收集器,標記-清楚演算法。四個步驟;初始標記,單執行緒stw,標記GC Roots能直接關聯到的物件,速度很快;併發標記,GC Roots Tracing(應該就是判斷復活吧,和被標記物件的變化);重新標記,修正併發標記期間因使用者程式繼續運作而導致標記變動的那一部分物件,多執行緒stw,時間比初始標記稍長,遠比並發標記短;併發清除,完成後重置執行緒為使用者執行緒。缺點,CPU資源敏感,在併發階段佔用CPU資源導致程式變慢;無法處理浮動垃圾,在併發過程中會產生新的垃圾,無法清理,而且在垃圾清理過程中出現CMS執行期間預留的記憶體無法滿足執行需求的時候,就會出現一次Concurrent Mode Failure失敗,這是啟用後備預案,臨時啟用Serial Old收集器;碎片整理由於CS是基於標記-清除演算法實現的,所以會出現大量空間碎片,當老年代有足夠空間卻沒有足夠連續空間分配記憶體時候觸發一次合併整理過程,stw時間會變長。
  • G1:優勢–併發與並行;分代收集;空間整合,整體上看是基於標記-整理演算法,從區域性(兩個Region)是基於複製演算法;可預測停頓。維護Remembered Set避免全堆掃描。操作步驟–初始標記標記GC Roots能直接關聯到的物件,並且修改TAMS值,讓下階段程式併發執行時候能在正確可用的Region中建立物件,stw單執行緒,時間很短;併發標記對堆中物件進行可達性分析,找出存活物件,耗時長;最終標記修正併發標記期間的變動,stw多執行緒,Remembered Set Logs合併到Remembered Set;篩選回收排序制定回收計劃,可並行可stw多執行緒,大部分是stw多執行緒。
  • 物件優先在Eden分配:當Eden區沒有足夠空間分配,進行Minor GC,複製到Survovir中的一個
  • 大物件直接進入老年代:超過-XX:PretenureSizeThreshold的物件直接放入老年代;長期存活的物件進入老年代,-XX:MaxTenuringThreshold設定;動態物件年齡判定,如果Survivor空間中的相同年齡物件的大小總和大於Survivor空間的一半,年齡大於或等於該年齡的物件進入老年代;空間分配擔保,Minor GC之前,如果老年代最大可用連續空間小於新生代物件總空間,則是安全;否則檢視HandlePromotionFailure是否允許擔保失敗;允許則檢查老年代可用連續空間是否大於歷次進入老年代的物件大小均值,否則都觸發FullGC