1.何為垃圾
在Java中,如果物件物體沒有參考指向的話,存盤該物體的記憶體便成為垃圾,JVM會有一個系統執行緒專門負責回收垃圾,垃圾同時包括分配物件記憶體間的碎片塊
2.垃圾處理包含的演算法
Java語言規范沒有明確地說明JVM使用哪種垃圾回收演算法,但是任何一種垃圾回收演算法一般要做2件基本的事情:(1)發現無用的資訊物件,(2)回收無用物件占據的記憶體,使得該記憶體可以被程式再次使用,
垃圾回收一面在回收記憶體,一面使堆中的記憶體緊密排列,下面介紹幾種演算法:
2-1參考計數法
該演算法使用參考計數器來區分存活物件和不再使用的物件,一般來說,堆中的每個物件對應一個參考計數器,當每一次創建一個物件并賦給一個變數時,參考計數器置為1,當物件被賦給任意變數時,參考計數器每次加1當物件出了作用域后(該物件丟棄不再使用)或者被置為null時,參考計數器減1,一旦參考計數器為0,物件就滿足了垃圾收集的條件,
基于參考計數器的垃圾收集器運行較快,不會長時間中斷程式執行,適宜必須實時運行的程式,但參考計數器增加了程式執行的開銷,因為每次物件賦給新的變數,計數器加1,而每次現有物件出了作用域,計數器減1,雖然管理參考計數的開銷不大,但是該開銷在整個程式的生命周期
2-2tracing演算法(標記-清除)
基于tracing演算法的垃圾收集也稱為標記和清除(mark-and-sweep)垃圾收集器,它所依據的思路是,從堆疊和靜態存盤區出發,遍歷所有的參考,找到存活的物件,每當找到一個存活的物件,就給該物件設一個標記,當標記作業全部完成時,清理作業才會開始,在清理的程序中,沒有標記的物件會被釋放,該方式相當慢,在產生少量垃圾和幾乎不產生垃圾的情況下速度就很快了,
2.3. compacting演算法(標記-整理)
為了解決堆碎片問題,基于compacting的垃圾回收吸收了tracing演算法的思想,在清除無用物件之后,演算法將所有的物件移到堆的一端,堆的另一端就變成了一個相鄰的空閑記憶體區,收集器會對它移動的所有物件的所有參考進行更新,使得這些參考在新的位置能識別原來的物件,解決了記憶體碎片的問題(不但進行了清理而且進行了物件的搬運,成本更高),在基于Compacting演算法的收集器的實作中,一般增加句柄和句柄表,
2.4. copying演算法
它開始時把堆分成一個物件區和多個空閑區,程式從物件區為物件分配空間,當物件滿了,基于coping演算法的垃圾回收就掃描活動物件,并將每個活動物件復制到空閑區(使得活動物件所占的記憶體之間沒有空閑間隔),這樣空閑區變成了物件區,原來的物件區變成了空閑區,程式會在新的物件區中分配記憶體,
一種典型的基于coping演算法的垃圾回收是stop-and-copy演算法,它將堆分成物件區和空閑區域區,在物件區與空閑區域的切換程序中,程式暫停執行,
2.5. generation演算法
stop-and-copy垃圾收集器的一個缺陷是收集器必須復制所有的活動物件,這增加了程式等待時間,這是coping演算法低效的原因,分代的垃圾回收策略,是基于這樣一個事實:不同的物件的生命周期是不一樣的,因此,不同生命周期的物件可以采取不同的回收演算法,以便提高回收效率,generation演算法將堆分成兩個或多個,每個子堆作為物件的一代(generation),1.所有新生成的物件首先都是放在年輕代的,年輕代的目標就是盡可能快速的收集掉那些生命周期短的物件,2.在年輕代中經歷了N次垃圾回收后仍然存活的物件,就會被放到年老代中,因此,可以認為年老代中存放的都是一些生命周期較長的物件,3.持久代用于存放靜態檔案,如Java類、方法等,持久代對垃圾回收沒有顯著影響,但是有些應用可能動態生成或者呼叫一些class,在這種時候需要設定一個比較大的持久代空間來存放這些運行程序中新增的類,
3.System.gc()方法
使用System.gc()可以不管JVM使用的是哪一種垃圾回收的演算法,都可以請求Java虛擬機進行垃圾回收,值得注意的是,JVM接受這個訊息后,并不是立即做垃圾回收(需要搶占CPU資源),而只是對幾個垃圾回收演算法做了加權,使垃圾回收操作容易發生,或提早發生,或回收較多而已,
盡量避免顯示的呼叫gc,若不針對GC的特點進行設計和編碼,就會出現記憶體駐留等一系列負面影響,此函式建議JVM進行主GC,雖然只是建議而非一定,但很多情況下它會觸發主GC,從而增加主GC的頻率,也即增加了間歇性停頓的次數,
4. finalize()方法
java垃圾處理器只能釋放哪些經由New出來的物件記憶體,對于其它途徑產生的記憶體,java允許在類中定義finalize()方法,在垃圾回收時候呼叫finalize(),處理記憶體,雖然不一定發生,但是當垃圾回收動作發生時,非new記憶體會被清理,finalize中添加一些非java能夠處理的垃圾,例如類似C語言中使用的malloc()函式分配的記憶體,除非呼叫free(),否則記憶體得不到釋放,造成泄露,所以,在finalize方法中呼叫free()方法,(free是C和C++的方法),當垃圾回收發生時,finalize()函式被呼叫,絕對不能直接呼叫finalize(),因為垃圾回收只與記憶體有關,無論物件是如何創建的,垃圾回收器都會負責釋放那些物件占有的記憶體,
當垃圾回收器確定不存在對該物件的更多參考時,由物件的垃圾回收器呼叫此方法,子類重寫 finalize 方法,以配置系統資源或執行其他清除,
java虛擬機在未面臨記憶體耗盡的情況下,不會浪費時間去執行垃圾回收以恢復記憶體的,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/174992.html
標籤:Java
上一篇:Keycloak快速上手指南,只需10分鐘即可接入Spring Boot/Vue前后端分離應用實作SSO單點登錄
下一篇:Spring Boot初學
