第一次編輯 2019-05-07 01:09:39 垃圾回收的對象 程式中的不可用對象(不存活的對象,沒有任何引用),或者無用的變數信息等,在程式中長期存在會逐漸占用較多的記憶體空間,導致沒有足夠的空間分配給新生成的對象等. 判斷哪些是需要回收的對象 早期jdk使用引用計數法,計數每個對象的引用次數, ...
第一次編輯 2019-05-07 01:09:39
垃圾回收的對象
程式中的不可用對象(不存活的對象,沒有任何引用),或者無用的變數信息等,在程式中長期存在會逐漸占用較多的記憶體空間,導致沒有足夠的空間分配給新生成的對象等.
判斷哪些是需要回收的對象
早期jdk使用引用計數法,計數每個對象的引用次數,對於沒有引用的對象進行刪除,但是該方法無法處理迴圈引用情況.
之後引入了可達性分析演算法,將所有的引用關係看作一張圖,從一個結點(GC ROOT)開始,尋找向下的引用結點,之後重覆這一過程,其中的路徑被稱為引用鏈,當一個對象沒有與GC ROOT相連的引用鏈時,該對象是不可用的
執行回收的時間
在CPU空閑時自動回收,或在堆記憶體滿後進行回收,或者程式中調用System.gc()後進行回收
執行回收的演算法
共有四種
- 1. 標記-清除演算法
分兩步執行,首先標記,根據可達性分析標記出所有需要回收的對象,之後對被標記的對象進行回收.
該方法不需要移動對象,只對不可用對象操作,較為簡單.但是一般情況下,效率較低,同時由於直接回收垃圾,會產生記憶體碎片,後續為較大對象分配空間時,可能因為無法找到較大的連續記憶體空間而必須再次進行垃圾回收過程
- 2. 複製演算法
將可用的記憶體按照容量大小等分,每次只使用一塊空間進行分配,當這一塊用完時,將可用對象移動到另一塊空間上,然後清理已經用過的空間.
該方法每次只需要對一半的空間進行回收,同時解決了記憶體碎片的問題.但是使用中浪費了一半的記憶體空間,在可用對象較多的情況下需要進行較多的複製,效率降低.
- 3. 標記-整理演算法
標記-清除法的改進.在使用標記-清除演算法回收不可用對象後,將所有可用的對象壓縮到記憶體的一端,之後清理端邊界之外的所有記憶體.
該方法解決了記憶體碎片的問題,但是增加了對象移動的過程,執行的成本較高
- 4. 分代收集演算法
目前主要使用的方法
根據對象存活的周期將記憶體(堆)分為多塊,一般是新生代,老年代和永生代(永久代).在不同的代使用不同的收集器(收集器使用不同的演算法)進行回收,提高效率.
新生代
儘快的收集生命周期短的對象.新生代內部一般被分為三個部分,分別是Eden區,survivor0區和survivor1區,分配的比例為8:1:1.新產生的對象首先被放置到Eden區,當該區被放置滿之後,將該區的存活對象移動到survivor0區,之後清空Eden區,當survivor0區也被放置滿時,將Eden區和survivor0區存活對象複製到survivor1區,之後清空Eden區和survivor0區.,交換survivro0區和survivor1區,即保持survivor1區為空,之後重覆該過程.
當survivor1區不夠存放eden區和survivor0區的存活對象時,將這些對象放入老年代.
在這個過程中的垃圾回收過程被稱為Minor GC(小型垃圾回收),該過程發生比較頻繁,不一定嚴格等待eden區滿才執行.該回收過程發生時,所有程式線程暫停,直到完成回收工作,是Stop the world(STW)事件的一種.
老年代
存放生命周期較長的對象.老年代的空間較新生代大,當老年代滿時觸發Major GC,該過程同樣導致STW,並且時間比Minor GC更長.
永久代
存放靜態文件,如類或方法等.一些運行過程中動態生成的類會被放置到這裡.
各代使用不同的回收器,新生代使用應用複製演算法的收集器,老年代使用應用標記-清除或標記-整理演算法的收集器
Java8廢棄了永久代,用元空間進行代替;在JDK1.7中推出了新的G1收集器.
參考如下
https://baijiahao.baidu.com/s?id=1610753983428990724&wfr=spider&for=pc
https://blog.csdn.net/weixin_39067991/article/details/81045201
https://blog.csdn.net/w372426096/article/details/81360083