Java提高——Java的記憶體回收(2)
Java的記憶體洩漏
記憶體洩漏:程式執行過程中,不斷的分配記憶體空間,那些不再使用的記憶體空間應該即時回收,,從而保證系統可以再次使用這些記憶體。如果存在無用的記憶體沒有被回收,那麼就是記憶體洩漏。
垃圾回收機制
垃圾回收機制主要完成以下兩件事:
1、跟蹤並監控每個Java物件,當某個物件處於不可達狀態則回收該物件所佔用的記憶體
2、清理記憶體分配、回收過程中產生的碎片
垃圾回收的基本演算法
實際上,垃圾回收機制不可能實時監測到每個Java物件的狀態,因此當一個物件失去引用之後,它不會被立即回收,只有等垃圾回收執行時才會被回收。
垃圾回收的涉及演算法大致如下:
序列回收和並行回收:序列回收就是無論多少個CPU,始終只用一個執行垃圾回收操作;並行回收就是把整個垃圾回收工作分成多個部分供多個CPU負責,讓多個CPU並行回收,效率很高,複雜度增加,但是產生的碎片很多。
併發執行和應用程式停止:應用程式停止的垃圾回收方式會導致應用程式的暫停,併發執行垃圾回收的方式需要解決和應用程式的衝突問題,因此開銷比較大。
壓縮和不壓縮和複製:
壓縮(標記壓縮):把所有活得物件搬到一起,將之前佔用得記憶體全部回收
不壓縮(標記清除):只是回收記憶體,且回收回來得記憶體是不連續的,會有更多碎片。(且回收回來的記憶體塊分配更慢,無法解決碎片問題)
複製:將所有物件複製到另一塊相同的記憶體中,不會產生記憶體碎片,但是需要複製資料和額外的記憶體。
現行的垃圾回收器用分代的方式來採用不同的回收設計。根據物件的生存時間長短,把堆記憶體分成3個代:
Yong(年輕代)、Old(老年代)、permanent(永久代)
堆記憶體分代回收
分代回收依據物件的生存時間的長短,然後根據不同代採取不同的垃圾回收策略。
採用“分代回收”的策略基於如下事實:
1、絕大多數的物件不會被長時間引用,這些物件在Yong期間就會被回收;
2、很老的物件和很新的物件之間很少存在相互引用。
一、Yong代
Yong代採用複製演算法,只需要遍歷那些處於不可達狀態的物件,而且物件的數量少,複製成本小,能充分發揮複製演算法的優勢
二、Old代
Old代垃圾回收具有如下兩個特徵:
1、Old代垃圾回收的執行頻率不會太高,因為很少有物件死掉
2、對每次Old代執行垃圾回收需要更長的時間來完成。
基於以上,通常採用標記壓縮演算法,避免複製Old代的大量物件,且不會大量產生碎片,比較划算。
三、Permanent代
Permanent代主要用於裝載Class、方法等資訊,預設64M,垃圾回收機制通常不會回收Permanent代中的物件。
常見垃圾回收器
1、序列回收器
對Yong代和Old代的回收都使用序列(只使用一個CPU),且執行期間會使程式暫停。Yong代採用串行復制演算法,Old代使用序列標記壓縮演算法。
2、並行回收器
Yong代與序列回收相似,只是啟用了多個CPU,多執行緒;Old代採用與序列回收相同的演算法,不管有幾個CPU都採用單執行緒、標記整理的方式進行回收。
3、並行壓縮回收器
4、併發標識-清理回收器(CMS)
記憶體管理小技巧
1、儘量使用直接量
如:String str = “123”;而不是String str = new String(“123”);
2、使用StringBuffer和StringBuilder進行字串連結
3、今早釋放無用物件
4、儘量少使用靜態變數
5、避免在經常呼叫的方法、迴圈中建立Java物件
6、快取經常使用的物件
7、儘量不要使用finalize方法
8、考慮使用SoftReference