GC回收垃圾对象过程
GC回收垃圾對象需要完成的三件事
1、哪些內存需要回收?
2、如何判斷對象是否該回收?
3、如何回收垃圾對象?
哪些內存需要回收
程序計數器、虛擬機棧、本地方法棧三個區域隨線程而生隨線程而滅。虛擬機棧中的棧幀隨著方法的開始和結束對應著入棧和出棧。每一個棧幀需分配內存的大小在類結構確定下來時就已知了。因此這幾個區域的內存分配和回收都具有確定性。方法結束時或是線程結束時內存會隨之回收。
Java堆和方法區不同,一個接口的實現類所需的內存可能不同,一個方法的不同分支所需內存也可能不同。只有在程序運行期才能知道要創建多少對象,這部分的內存分配和回收具有動態性。
如何判斷對象是否該回收
引用計數算法
給對象添加一個引用計數器,每當有一個地方引用該對象時計數器加1,有一個地方的引用失效時計數器減1,計數器為0的對象判定為不可用。但是主流的虛擬機沒有選用該算法原因是無法解決對象之間互相循環引用的問題。
可達性分析算法
該算法思路是通過一系列稱為"GC Roots "的對象作為起始點開始向下搜索,搜索走過的路徑稱為引用鏈(Reference?Chain)。當一個對象到GC?Roots沒有任何引用鏈相連接時則證明此對象不可用。
雖然5、6、7對象互相引用,但是他們到GC?Roots是不可達的,他們將被判定為可回收的對象。
可作為GC?Roots的對象
虛擬機棧(棧幀中的本地變量表)中引用的對象
方法區中靜態屬性引用的對象
方法區中常量引用的對象
本地方法棧(Native方法)中引用的對象
對象引用
強引用
該引用普遍存在如Object?obj = new Object();,只要強引用還存在垃圾收集器將不能回收掉被引用的對象。
軟引用
該引用描述的是還有用但是非必須的對象。對于軟引用著的對象在系統發生內存溢出異常之前會回收該對象,如果內存不夠才會拋出內存溢出異常。SoftReference類實現軟引用。
弱引用
該引用描述非必須的對象。對于弱引用著的對象只能存活到下一次垃圾收集器觸發之前,無論內存是否足夠都會回收該對象。WeakReference類實現弱引用。
虛引用
該引用不會對對象的生存時間產生影響而且我們無法通過該引用獲得對象實例。唯一的作用是當對象被回收時收到一個系統通知。PhantomReference類實現虛引用。?
回收方法區
方法區的垃圾收集行為比較少,主要是收集廢棄常量和無用的類。
廢棄常量容易判定,無用的類需滿足三個條件才能判定類是無用的
該類的所有實例已被回收,堆中沒有類的任何實例
加載該類的類加載器已經被回收
該類的java.lang.Class對象沒有在任何地方被引用,在任何地方無法通過反射訪問其方法
在大量使用反射、動態代理的框架、動態生成JSP及OSGI這類頻繁自定義ClassLoader的場景都需要虛擬機有類卸載功能保證方法區不會溢出
如何回收垃圾對象 (垃圾收集算法)
標記-清除算法
首先標記要回收的對象,標記完成后統一回收所有被標記的對象。不足是標記和清除效率都不高,標記清除后產生不連續的空間碎片。
復制算法
將可用內存劃分為大小相等的兩塊,每次只用其中一塊,用完之后將活著的對象復制到另一塊上,然后將用過的那塊一次性清除。當前虛擬機對新生代都使用該算法,將內存分為一個塊較大的Eden和兩塊較小的Survivor空間,每次使用一塊Eden和一塊Survivor,回收時將存活的對象復制到另一塊Survivor中。當Survivor空間不足時依賴其他內存(老年代)進行分配擔保。
標記-整理算法
標記和標記-清除算法算法一樣,接下來不是直接對可回收的對象進行回收,而是讓所有的存活對象向一段移動,然后清除掉端邊界外的內存。
分代收集算法
當前虛擬機都采用該算法,將Java堆分為新生代和老年代。新生代中每次GC時都會有大量對象死去,少部分存活選用復制算法。老年代對象存活率較高,沒有額外內存進行分配擔保必須使用標記-清除或標記-整理算法。
?
轉載于:https://www.cnblogs.com/BINGJJFLY/p/7610684.html
總結
以上是生活随笔為你收集整理的GC回收垃圾对象过程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 上传文件input(type=file)
- 下一篇: Glide 这样用,更省内存!!!