您好,登錄后才能下訂單哦!
本篇內容介紹了“GC算法與四種引用有哪些”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
GC
算法常見的GC
算法包括:
引用計數(shù)法
標記清除法
復制算法
標記壓縮法
分代算法
分區(qū)算法
實現(xiàn)原理:
對于一個對象A
只要有任何一個對象引用A,A的引用計數(shù)器就加1
引用失效時,引用計數(shù)器就減1
只要對象A的引用計數(shù)器的值為0,對象A就不會再被使用,等待被回收
缺點:
無法處理循環(huán)引用,比如A引用B,B引用A,但是并沒有其他對象引用兩者,此時A和B的引用計數(shù)都不為0,這樣就無法被回收
引用計數(shù)器要求每次引用產生和消除的時候,伴隨一個加法操作和一個減法操作,對系統(tǒng)性能會有一定的影響
由于引用計數(shù)法上述的缺點,Java
中并未采用作為GC
算法。
標記清除法將垃圾回收分為兩個階段:
標記階段:通過根節(jié)點標記所有從根節(jié)點開始的可達對象,未被標記的就是垃圾對象
清除階段:清除所有未被標記的對象
標記階段:
清除后:
缺點很明顯,就是回收后的空間是不連續(xù)的,工作效率會低于連續(xù)的內存空間。
核心思想:
內存空間分為相等的兩塊
每次只使用其中一塊
回收的時候將存活對象移到另一塊中,然后清除正在使用的內存塊中所有對象
交換兩個內存塊的角色
優(yōu)點是回收后的內存空間是沒有碎片的,而缺點是如果存在大量的對象,需要花費大量的時間復制,并且內存只有原來的一半。
比如下圖中的A、B兩塊相同的內存空間,A在垃圾回收的時候,將存活對象復制到B中,B在復制后保持連續(xù):
復制完成后,A會被清空,并將B設置為當前使用的空間。
在Java
的新生代串行垃圾回收器中,使用了復制算法,新生代分為eden
區(qū)、from
區(qū)以及to
區(qū)。其中from
和to
區(qū)是兩塊內存相同的空間,也叫survivor
區(qū),也就是幸存者空間。在垃圾回收的時候,eden
區(qū)以及from
區(qū)存活的對象會被復制到to
區(qū),然后清空from
區(qū)與eden
區(qū),接著from
和to
區(qū)的角色將會交換,也就是下一次垃圾回收的時候,會從原來的to
區(qū)(新的from
區(qū))復制到原來的from
區(qū)(新的to
區(qū))。
標記壓縮法是一種老年代算法,在標記清除法的基礎上做了一些優(yōu)化,和標記清除法一樣,首先也需要從根節(jié)點開始,對所有可達對象做一次標記,然后將所有存活對象壓縮到內存的一端,接著清理邊界外的所有空間,圖示如下:
標記壓縮法的優(yōu)點是可以避免碎片的產生,又不需要兩塊相同的內存空間。
分代算法并不是一種具體的垃圾回收算法,分代算法其實是一種根據(jù)每塊內存空間的特點使用不同回收算法以提高效率的算法。比如:
在新生代中:會有大量的新建對象很快被回收,因此新生代比較適合使用復制算法
在老年代中:采用標記壓縮法或標記清除法
分區(qū)算法將整個堆空間劃分成連續(xù)的不同小區(qū)間,每個小區(qū)間都獨立使用,獨立回收,如圖所示:
3 四種引用
Java
里面提供了4個級別的引用:
強引用
軟引用
弱引用
虛引用
下面分別來看一下。
強引用就是代碼中一般使用的引用類型,強引用的對象是可觸及的,不會被回收,比如:
StringBuffer str = new StringBuffer("a");
如果上面的代碼運行在方法體內,那么局部變量str
會被分配在棧上,而對象StringBuffer
實例會被分配在堆上,str
指向的是StringBuffer
實例所在的堆空間,通過str
可以操作該實例,str
就是StringBuffer
實例的強引用。
又比如執(zhí)行了以下代碼:
StringBuffer str1 = str;
那么str1
也會指向str
指向的對象,也就是它們都指向同一個StringBuffer
實例,此時str1==str
的值為真,因為兩個指向的是同一個堆空間地址。
強引用的特點如下:
可以直接訪問目標對象
強引用指向的對象不會被系統(tǒng)回收,JVM
寧愿拋出OOM
也不會回收強引用指向的對象
強引用可能會導致內存泄漏
軟引用是被強引用弱一點的引用類型,如果一個對象只持有軟引用,那么當堆空間不足的時候,就會被回收,軟引用可以使用SoftReference
類實現(xiàn),比如下面的代碼:
public static void main(String[] args){ Byte[] b = new Byte[1024*1024*8]; SoftReference<Byte[]> softReference = new SoftReference<>(b); b = null; System.out.println(softReference.get()); System.gc(); System.out.println("After GC"); System.out.println(softReference.get()); b = new Byte[1024*1024*8]; System.gc(); System.out.println(softReference.get()); }
在OpenJDK 11.0.10
上,加上-Xmx40m
的輸出如下:
[Ljava.lang.Byte;@1fbc7afb After GC [Ljava.lang.Byte;@1fbc7afb null
可以看到,當垃圾回收的時候,未必會回收軟引用對象,但當內存緊張時,會回收軟引用對象。
弱引用是比軟引用弱的引用類型,在垃圾回收的時候,只要發(fā)現(xiàn)弱引用,不管系統(tǒng)空間使用情況如何,都會將對象進行回收。但是由于垃圾回收器的線程通常優(yōu)先級不高,并不一定能很快發(fā)現(xiàn)弱引用對象,這種情況下弱引用對象可以存在較長時間。弱引用例子如下:
public static void main(String[] args){ Byte[] b = new Byte[1024*1024*8]; WeakReference<Byte[]> softReference = new WeakReference<>(b); b = null; System.out.println(softReference.get()); System.gc(); System.out.println("After GC"); System.out.println(softReference.get()); }
輸出(-Xmx40m
):
[Ljava.lang.Byte;@1fbc7afb After GC null
可以看到在GC
后,弱引用對象會被立即回收。
軟引用、弱引用的一個常見使用場景是保存可有可無的緩存數(shù)據(jù),當系統(tǒng)內存不足時,這些內存數(shù)據(jù)會被回收,不會導致OOM
,而內存充足時,這些緩存數(shù)據(jù)又可以存在相當長的時間,從而起到讓系統(tǒng)加速的作用。
虛引用是所有引用類型中最弱的一個,一個持有虛引用的對象和沒有引用幾乎是一樣的,隨時都可能被垃圾回收器回收。另外,試圖使用虛引用的get()
方法獲取強引用的時候,總是會失敗,并且虛引用需要和引用隊列一起使用,作用在與跟蹤垃圾回收過程。
public static void main(String[] args) throws Exception { ReferenceQueue<String> queue = new ReferenceQueue<>(); PhantomReference<String> reference = new PhantomReference<>(new String("test"),queue); System.out.println(reference.get()); }
輸出結果:
null
“GC算法與四種引用有哪些”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。