分配出去的內(nèi)存得不到及時的回收,就會引起系統(tǒng)運行速度下降、甚至導(dǎo)致程序癱瘓,這種現(xiàn)象被稱為內(nèi)存泄漏察蹲。
C/C++等編程語言使用的是 顯式垃圾回收:是由程序員直接進行控制內(nèi)存回收。顯式垃圾回收有以下兩個缺點催训。
1洽议、程序忘記計時回收無用內(nèi)存,從而導(dǎo)致內(nèi)存泄漏漫拭,降低系統(tǒng)性能亚兄,
2、程序錯誤的回收程序核心類庫的內(nèi)存采驻,從而導(dǎo)致程序崩潰审胚。
java的內(nèi)存分配和回收都是由JRE在后臺自動進行的,JRE會負責(zé)回收哪些不再使用的內(nèi)存礼旅,這種機制被稱為垃圾回收(Garbage Collection ,GC),JRE會提供一個后臺線程來進行檢測和控制膳叨,一般都是在CPU空閑或者內(nèi)存不足時自動進行垃圾回收,程序員無法精確控制垃圾回收的時間和順序等痘系。
java的堆內(nèi)存是一個運行時數(shù)據(jù)區(qū)菲嘴,用以保存類的實例,java虛擬機的堆內(nèi)存中存儲著正在運行的應(yīng)用程序所建的所有對象,這些對象不需要程序通過代碼來顯式的釋放龄坪。堆內(nèi)存的回收是由垃圾回收來負責(zé)的昭雌,所有的JVM實現(xiàn)都有一個由垃圾回收器管理的堆內(nèi)存,垃圾回收是一種觀念動態(tài)存儲管理技術(shù)悉默。會自動釋放不再被程序引用的對象。按照特定的垃圾回收算法來實現(xiàn)內(nèi)存資源的自動回收功能苟穆。
在java中抄课,當(dāng)沒有引用變量指向原先分配給某個其他對象的內(nèi)存時,該內(nèi)存便成為垃圾雳旅,JVM的一個超級線程會自動釋放該內(nèi)存區(qū)跟磨,垃圾回收意味著程序不再需要的對象是‘垃圾信息’,這些信息將被丟棄攒盈。當(dāng)一個對象不再被引用時抵拘,內(nèi)存回收其占領(lǐng)的空間。以便空間被新的對象使用型豁,除了釋放沒用的對象外僵蛛,垃圾回收也可以清楚內(nèi)存記錄碎片,由于創(chuàng)建對象和垃圾回收器釋放丟棄對象所占用的內(nèi)存空間迎变,內(nèi)存就會出現(xiàn)碎片充尉,碎片是分配給對象的內(nèi)存塊之間的空閑內(nèi)存區(qū),碎片整理將所占用的堆內(nèi)存移到堆的一端衣形,JVM將整理出來的內(nèi)存分配給新的對象驼侠。垃圾回收能自動釋放內(nèi)存空間,優(yōu)點:
1谆吴、垃圾回收機制能很好的提高編程效率倒源,不需要花費時間解決難懂的存儲器問題。
2句狼、垃圾回收機制保護程序的完整性笋熬。
垃圾回收潛在的缺點:他的開銷會影響程序性能,JVM必須跟蹤程序中所有的對象腻菇,才能確定哪些對象是無用的對象突诬,并最終釋放這些對象。這個過程是需要花費時間的芜繁。垃圾回收有一下幾個特點:
1旺隙、垃圾回收機制的工作目標是回收無用的對象的內(nèi)存空間,只能回收內(nèi)存資源骏令,對其他物理資源如數(shù)據(jù)庫連接蔬捷,磁盤I/O等資源則無法回收。
2、為了更快的讓垃圾回收機制回收哪些不再使用的對象周拐,可以將對象的引用變量設(shè)置為null铡俐,通過這種方式暗示垃圾回收機制可以回收該對象。
3妥粟、垃圾回收發(fā)生的不可預(yù)知性审丘,由于不同JVM才用了不同的垃圾回收機制和不同的垃圾回收算法,所以有可能是定時發(fā)生勾给,有可能是當(dāng)CPU空閑時發(fā)生滩报,也可能和原始的垃圾回收機制一樣,等到內(nèi)存消耗出現(xiàn)極限時發(fā)生播急,與垃圾回收機制的選擇和具體的設(shè)置有關(guān)脓钾。程序員可以通過調(diào)用Runtime對象的gc()或者System.gc()等方法建議系統(tǒng)進行垃圾回收。
4桩警、垃圾回收的精確性包括兩方面:一是垃圾回收機制能夠精確的標記活著的對象可训,前提是完全回收所有的廢棄對象,否則則會造成內(nèi)存泄漏捶枢,二是垃圾回收器能夠精確的定位對象之間的引用握截,他是實現(xiàn)歸并和復(fù)制等算法的必要條件,通過這種引用關(guān)系可以保證所有的對象都能被可靠的回收烂叔。所有對象都能被重新分配川蒙,從而有效的減少內(nèi)存碎片的產(chǎn)生。
典型的垃圾收集算法
在確定了哪些垃圾可以被回收后长已,垃圾收集器要做的事情就是開始進行垃圾回收畜眨,但是這里面涉及到一個問題是:如何高效地進行垃圾回收。由于Java虛擬機規(guī)范并沒有對如何實現(xiàn)垃圾收集器做出明確的規(guī)定术瓮,因此各個廠商的虛擬機可以采用不同的方式來實現(xiàn)垃圾收集器康聂,所以在此只討論幾種常見的垃圾收集算法的核心思想。
1.Mark-Sweep(標記-清除)算法
這是最基礎(chǔ)的垃圾回收算法胞四,之所以說它是最基礎(chǔ)的是因為它最容易實現(xiàn)恬汁,思想也是最簡單的。標記-清除算法分為兩個階段:標記階段和清除階段辜伟。標記階段的任務(wù)是標記出所有需要被回收的對象氓侧,清除階段就是回收被標記的對象所占用的空間。具體過程如下圖所示:
從圖中可以很容易看出標記-清除算法實現(xiàn)起來比較容易导狡,但是有一個比較嚴重的問題就是容易產(chǎn)生內(nèi)存碎片约巷,碎片太多可能會導(dǎo)致后續(xù)過程中需要為大對象分配空間時無法找到足夠的空間而提前觸發(fā)新的一次垃圾收集動作。
2.Copying(復(fù)制)算法
為了解決Mark-Sweep算法的缺陷旱捧,Copying算法就被提了出來独郎。它將可用內(nèi)存按容量劃分為大小相等的兩塊踩麦,每次只使用其中的一塊。當(dāng)這一塊的內(nèi)存用完了氓癌,就將還存活著的對象復(fù)制到另外一塊上面谓谦,然后再把已使用的內(nèi)存空間一次清理掉,這樣一來就不容易出現(xiàn)內(nèi)存碎片的問題贪婉。具體過程如下圖所示:
這種算法雖然實現(xiàn)簡單反粥,運行高效且不容易產(chǎn)生內(nèi)存碎片,但是卻對內(nèi)存空間的使用做出了高昂的代價疲迂,因為能夠使用的內(nèi)存縮減到原來的一半才顿。
很顯然,Copying算法的效率跟存活對象的數(shù)目多少有很大的關(guān)系鬼譬,如果存活對象很多娜膘,那么Copying算法的效率將會大大降低逊脯。
3.Mark-Compact(標記-整理)算法
為了解決Copying算法的缺陷优质,充分利用內(nèi)存空間,提出了Mark-Compact算法军洼。該算法標記階段和Mark-Sweep一樣巩螃,但是在完成標記之后,它不是直接清理可回收對象匕争,而是將存活對象都向一端移動避乏,然后清理掉端邊界以外的內(nèi)存。具體過程如下圖所示:
4.Generational Collection(分代收集)算法
分代收集算法是目前大部分JVM的垃圾收集器采用的算法甘桑。它的核心思想是根據(jù)對象存活的生命周期將內(nèi)存劃分為若干個不同的區(qū)域拍皮。一般情況下將堆區(qū)劃分為老年代(Tenured Generation)和新生代(Young Generation),老年代的特點是每次垃圾收集時只有少量對象需要被回收跑杭,而新生代的特點是每次垃圾回收時都有大量的對象需要被回收铆帽,那么就可以根據(jù)不同代的特點采取最適合的收集算法。
目前大部分垃圾收集器對于新生代都采取Copying算法德谅,因為新生代中每次垃圾回收都要回收大部分對象爹橱,也就是說需要復(fù)制的操作次數(shù)較少,但是實際中并不是按照1:1的比例來劃分新生代的空間的窄做,一般來說是將新生代劃分為一塊較大的Eden空間和兩塊較小的Survivor空間愧驱,每次使用Eden空間和其中的一塊Survivor空間,當(dāng)進行回收時椭盏,將Eden和Survivor中還存活的對象復(fù)制到另一塊Survivor空間中组砚,然后清理掉Eden和剛才使用過的Survivor空間。而由于老年代的特點是每次回收都只回收少量對象掏颊,一般使用的是Mark-Compact算法惫确。注意,在堆區(qū)之外還有一個代就是永久代(Permanet Generation),它用來存儲class類改化、常量掩蛤、方法描述等。對永久代的回收主要回收兩部分內(nèi)容:廢棄常量和無用的類陈肛。
典型的垃圾收集器
垃圾收集算法是 內(nèi)存回收的理論基礎(chǔ)揍鸟,而垃圾收集器就是內(nèi)存回收的具體實現(xiàn)。下面介紹一下HotSpot(JDK 7)虛擬機提供的幾種垃圾收集器句旱,用戶可以根據(jù)自己的需求組合出各個年代使用的收集器阳藻。
1.Serial/Serial Old
Serial/Serial Old收集器是最基本最古老的收集器,它是一個單線程收集器谈撒,并且在它進行垃圾收集時腥泥,必須暫停所有用戶線程。Serial收集器是針對新生代的收集器啃匿,采用的是Copying算法蛔外,Serial Old收集器是針對老年代的收集器,采用的是Mark-Compact算法溯乒。它的優(yōu)點是實現(xiàn)簡單高效夹厌,但是缺點是會給用戶帶來停頓。
2.ParNew
ParNew收集器是Serial收集器的多線程版本裆悄,使用多個線程進行垃圾收集矛纹。
3.Parallel Scavenge
Parallel Scavenge收集器是一個新生代的多線程收集器(并行收集器),它在回收期間不需要暫停其他用戶線程光稼,其采用的是Copying算法或南,該收集器與前兩個收集器有所不同,它主要是為了達到一個可控的吞吐量艾君。
4.Parallel Old
Parallel Old是Parallel Scavenge收集器的老年代版本(并行收集器)采够,使用多線程和Mark-Compact算法。
5.CMS
CMS(Current Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器腻贰,它是一種并發(fā)收集器吁恍,采用的是Mark-Sweep算法。
6.G1
G1收集器是當(dāng)今收集器技術(shù)發(fā)展最前沿的成果播演,它是一款面向服務(wù)端應(yīng)用的收集器冀瓦,它能充分利用多CPU、多核環(huán)境写烤。因此它是一款并行與并發(fā)收集器翼闽,并且它能建立可預(yù)測的停頓時間模型。