摘要:這個算法看似不錯而且簡單,不過存在這一個致命傷當兩個對象互相引用的時候,就永遠不會被回收于是引用計數算法就永遠回收不了這兩個對象,下面介紹另一種算法。
前言
? 如果要問Java與其他編程語言最大的不同是什么,我第一個想到的一定就是Java所運行的JVM所自帶的自動垃圾回收機制,以下是我學習JVM垃圾回收機制整理的筆記,希望能對讀者有一些幫助。
? 如何判斷對象已死?有兩種算法
引用計數算法? 給對象添加一個計數器,每當有一個地方引用它時,計數器的值就加一,當引用失效的時候,計數器就減一 ,任何時刻計數器為0的對象就是不可能再被使用的時候。
? 這個算法看似不錯而且簡單,不過存在這一個致命傷(當兩個對象互相引用的時候,就永遠不會被回收)
public class Obj{ public Object instance=null; } Obj a=new Obj(); Obj b=new Obj(); a.instance=b; b.instance=a; a=null; b=null;
于是引用計數算法就永遠回收不了這兩個對象,下面介紹另一種算法。
可達性分析算法? 通過一系列被稱為“GC Roots”的對象作為起始點,從這些接點向下搜索,搜索所走過的路徑稱為引用鏈,當一個對象與任何一個引用鏈沒有關聯的時候則可以被回收。
Java中,可作為GC Roots的對象包括下面集中
虛擬機棧(棧幀中的本地變量表)中引用的對象
方法區中類靜態屬性引用的對象
方法區中常量引用的對象
本地方法棧中JNI(Native方法)引用的對象
淺談引用? 無論是計數器算法還是可達性分析算法,都與“引用”有關,下面是Java中4種引用,強度依次減弱
? 強引用就是我們平時最熟悉的
Object obj=new Object();
? 只要強引用還存在,垃圾收集器永遠不會回收掉被引用的對象。
? 發生gc的時候,如果JVM內存充足則不回收,用SoftReference類來實現軟引用。展示一個例子
SoftReference
? 以下是輸出
before gc java.lang.Object@2752f6e2 after gc java.lang.Object@2752f6e2
可以看到軟引用的對象依然還在。
? 一旦發生gc,無論JVM內存充足與否,都會回收掉,用WeakReference類來實現弱引用。展示一個例子
WeakReference
? 以下是輸出
before gc java.lang.Object@2752f6e2 after gc null
弱引用的對象已經被回收!
? 虛引用也稱為幽靈引用或者幻影引用,是最弱的一種引用,無法通過虛引用來取得一個對象實例,擁有虛引用的對象可以在任何時候被垃圾回收器回收。唯一的目的就是能在當這個對象被回收的時候收到一個系統通知,可用PhantomReference類實現虛引用。
回收方法區? 垃圾回收大多發生在Heap(堆區),因為在方法區進行垃圾回收效率較低,要判定一個類是否是“無用的類”條件比較苛刻,類需要同時滿足下面3個條件才能算是無用的類
該類所有實例已經被回收,堆中不存在該類任何實例
加載該類的ClassLoader已經被回收
該類對應的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法。
什么時候回收?when?? 首先,GC又分為minor GC 和 Full Gc(也稱為Major GC)。Java 堆內存分為新生代和老年代,新生代中又分為1個Eden區域 和兩個 Survivor區域。
那么對于 Minor GC 的觸發條件:大多數情況下,直接在 Eden 區中進行分配。如果 Eden區域沒有足夠的空間,那么就會發起一次 Minor GC;對于 Full GC(Major GC)的觸發條件:也是如果老年代沒有足夠空間的話,那么就會進行一次 Full GC。
注意:上面所說的只是一般情況,實際上,需要考慮一個空間分配擔保的問題:
在發生Minor GC之前,虛擬機會先檢查老年代最大可用的連續空間是否大于新生代所有對象的總空間。如果大于則進行Minor GC,如果小于則看HandlePromotionFailure設置是否允許擔保失敗(不允許則直接Full GC)。如果允許,那么會繼續檢查老年代最大可用的連續空間是否大于歷次晉升到老年代對象的平均大小,如果大于則嘗試Minor GC(如果嘗試失敗也會觸發Full GC),如果小于則進行Full GC。
System.gc()就是指的Full GC
但是,具體程序執行到什么位置才會自動gc,這兒提兩個概念Safepoint和SafeRegion。
安全點(Safepoint)? 安全點的選定是以程序“是否具有讓程序長時間執行的特征”為標準選定的,“長時間執行”最明顯的特征就是
指令序列復用
循環跳轉
異常跳轉等
對于Safepoint如何在GC發生時讓所有線程都跑到最近的安全點上停下來,有兩種方案搶先式中斷和主動式中斷。
搶先式中斷:不需要線程執行的代碼主動配合,GC發生時,首先把所有線程全部中斷,如果發現有線程中斷的地方不在安全點上,就恢復線程,讓它“跑到”安全點上。(這種方案幾乎很少使用)
主動式中斷 :當GC需要中斷線程的時候,不直接對線程操作,僅僅簡單設置一個標志,各個線程執行時主動去輪詢這個標志,發現為true就自動掛起,輪詢的地方和安全點是重合的。
安全區域(Saferegion)? 當線程處于Sleep狀態或者Blocked狀態,這時候線程無法響應JVM的中斷請求,“走”到安全的地方去中斷掛起,JVM也顯然不太可能等待線程重新被分配CPU時間,這時候就需要安全區域來解決。
? 當線程執行到Safe Region中的代碼時,首先標識自己已經進入了Safe Region,當JVM在發起GC時,就不用管標識自己為Safe Region狀態的線程了。在線程要離開Safe Region時,他要檢查系統是否完成了整個GC過程,如果完成了,線程就繼續執行,否則必須等待直到收到可以安全離開Safe Region的信號為止。
如何回收?how? 標記-清除 算法? 算法分為標記和清除兩個階段,首先標記出所有需要回收的對象,在標記完成后統一回收所有被標記的對象。他的不足主要有兩個:
效率問題:標記和清除兩個過程的效率都不高
空間問題:標記清除之后,會產生大量不連續的內存碎片,空間碎片太多可能會導致之后分配大對象時,無法找到足夠的連續內存而提前觸發GC
復制算法? 復制算法可以將容量劃分為大小相等的兩塊,每次只使用其中的一塊,當一塊內存被用完了就將還存活的對象一次復制到另一塊內存上,然后把已經使用過的內存一次清理掉。不過因此內存縮小為原來的一半,代價過高。
? 現在的商業虛擬機普遍采用這種算法來回收新生代,將新生代分為較大的一塊Eden空間和兩塊較小的Survivor空間,HotSpot默認其比例為8:1:1,使用時,每次使用Eden加上其中一塊Survivor,回收時,將Eden和Survivor中還存活的對象一次性復制到另一塊Survivor中,最后清理掉Eden和剛才用過的Survivor區。
標記-整理 算法? 標記過程與“標記-清除”算法一樣,然后讓所有存活的對象都向同一端移動,然后直接清理端邊界以外的內存。
分代收集算法? 將Java堆分為新生代和老年代,在新生代中每次垃圾回收都有大批對象死去,少量存活,可以使用復制算法,而老年代中對象存活率高沒有額外的空間對它進行分配擔保,必須使用“標記-整理”或者“標記-清理”算法來回收。
談談G1垃圾收集器? 在最近更新的JDK9中,JVM默認的垃圾收集器切換成了G1,那么G1有什么特點呢?總結以下最大的四個特點
并行與并發:G1能充分利用多CPU、多核環境下的硬件優勢,使用多個CPU,(CPU或者CPU核心)來縮短Stop-The-World停頓的時間,部分其他收集器需要停頓Java線程執行的GC動作,G1可以通過并發的方式讓Java繼續執行。
分代收集:G1不需要其他收集器配合就能獨立管理整個GC堆,G1采用不同的方式去處理新創建的對象、已經存活一段時間的對象、熬過多次GC的舊對象以獲取更好的收集效果。
空間整合:G1從整體來看是基于“標記-整理”算法,局部上來看是基于復制算法,這兩種算法都不會產生內存碎片,有利于程序長時間運行。
可預測的停頓:G1除了追求低停頓外,還能建立可預測的停頓時間模型,能讓使用者明確指定在一個長度為M毫秒的時間片段內,消耗在垃圾收集上的時間不超過N毫秒。
資料來源《深入理解Java虛擬機》P61-P84
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69424.html
摘要:還記得剛開始學習的時候,內存管理前端掘金作為一門高級語言,并不像低級語言那樣擁有對內存的完全掌控。第三方庫的行代碼內實現一個前端掘金前言本文會教你如何在行代碼內,不依賴任何第三方的庫,用純實現一個。 (譯) 如何使用 JavaScript 構建響應式引擎 —— Part 1:可觀察的對象 - 掘金原文地址:How to build a reactive engine in JavaSc...
摘要:還記得剛開始學習的時候,內存管理前端掘金作為一門高級語言,并不像低級語言那樣擁有對內存的完全掌控。第三方庫的行代碼內實現一個前端掘金前言本文會教你如何在行代碼內,不依賴任何第三方的庫,用純實現一個。 (譯) 如何使用 JavaScript 構建響應式引擎 —— Part 1:可觀察的對象 - 掘金原文地址:How to build a reactive engine in JavaSc...
摘要:用戶態不能干擾內核態所以指令就有兩種特權指令和非特權指令不同的狀態對應不同的指令。非特權指令所有程序均可直接使用。用戶態常態目態執行非特權指令。 這是我今年從三月份開始,主要的大廠面試經過,有些企業面試的還沒來得及整理,可能有些沒有帶答案就發出來了,還請各位先思考如果是你怎么回答面試官?這篇文章會持續更新,請各位持續關注,希望對你有所幫助! 面試清單 平安產險 飛豬 上汽大通 浩鯨科...
摘要:執行過程引擎會加載源代碼,把它分解成字符串又叫做分詞,再把這些字符串轉換成編譯器可以理解的字節碼,然后執行這些字節碼。接著四個進程開始參與進來,分析和執行解析器所生成的字節碼。 JavaScript運行原理 知其然,也要知其所以然,這里主要談一談對JavaScript運行原理的理解。 JAVA虛擬機 首先我們從JAVA虛擬機說起。 首先說一下為什么要做成虛擬機,因為機器不同,如果沒有虛...
摘要:目錄介紹問題匯總具體問題好消息博客筆記大匯總年月到至今,包括基礎及深入知識點,技術博客,學習筆記等等,還包括平時開發中遇到的匯總,當然也在工作之余收集了大量的面試題,長期更新維護并且修正,持續完善開源的文件是格式的同時也開源了生活博客,從年 目錄介紹 00.Java問題匯總 01.具體問題 好消息 博客筆記大匯總【16年3月到至今】,包括Java基礎及深入知識點,Android技...
閱讀 3162·2023-04-25 17:19
閱讀 616·2021-11-23 09:51
閱讀 1339·2021-11-08 13:19
閱讀 776·2021-09-29 09:34
閱讀 1673·2021-09-28 09:36
閱讀 1494·2021-09-22 14:59
閱讀 2708·2019-08-29 16:38
閱讀 2053·2019-08-26 13:40