P6程序員應掌握的Java垃圾回收機制常識,你掌握多少?

什麼是垃圾回收機制?

垃圾回收的本質就是釋放垃圾佔用的空間,在Java中這個垃圾就是指:當程序創建對象,數組等引用類型實體時,系統會在堆內存中為之分配一塊內存區,對象就保存在內存區中,當內存不再被任何引用變量引用時,這塊內存就變成了“垃圾”,等待垃圾回收機制去進行回收。

垃圾回收GC(Garbage Collection)也算是Java裡的一大特色,因為問到GC,就繞不開JVM調優問題,這是後話,先看兩個問題:

1、什麼時候回收?

由於程序無法精準控制垃圾回收的運行,則垃圾回收在合適的時候進行,當對象永久性失去了引用後,系統就會在合適的時間回收它所佔的內存。

2、如何取消回收?

在垃圾回收機制回收任何對象之前,總會調用它的finalize()方法,該方法可能使該對象重新復活(使用一個引用變量重新去引用該對象),從而導致垃圾回收機制取消回收。

P6程序員應掌握的Java垃圾回收機制常識,你掌握多少?


那麼如何初步判斷對象是否可以被回收?

在Java中,要操作對象,就要通過引用來進行,於是可以通過引用計數來判斷一個對象是否可以被回收。通常而言,如果如果一個對象沒有任何引用與之關聯,則說明該對象基本不太可能在其他地方被使用到,那麼這個對象就成為可被回收的對象了,也就是引用計數法。來,看代碼:


public class Main {

public static void main(String[] args) {

MyObject object1 = new MyObject();

MyObject object2 = new MyObject();

object1.object = object2;

object2.object = object1;

object1 = null;

object2 = null;

}

}

class MyObject{

public Object object = null;

}

在什麼情況下可以將對象判定為可回收對象?先說比較簡單的三種:

1)顯示地將某個引用賦值為null或者將已經指向某個對象的引用指向新的對象,比如下面的代碼:

Object obj = new Object();

obj = null;

Object obj1 = new Object();

Object obj2 = new Object();

obj1 = obj2;

2)局部引用所指向的對象,比如下面這段代碼:

void fun() {

.....

for(int i=0;i<10;i++) {

Object obj = new Object();

System.out.println(obj.getClass());

}

}

循環每執行完一次,生成的Object對象都會成為可回收的對象。

3)只有弱引用與其關聯的對象,比如:

WeakReference<string> wr = new WeakReference<string>(new String("world"));/<string>/<string>


P6程序員應掌握的Java垃圾回收機制常識,你掌握多少?


如何強制回收垃圾?

當一個對象失去引用後,系統何時調用它的finalize()方法對它進行資源清理,何時它可以變成不可達狀態,系統何時回收它佔有的內存,對於程序完全透明。程序只能控制一個對象不再被任何引用變量引用,不能控制它何時被回收。

程序可以強制系統進行垃圾回收——這種強制只是通知系統進行垃圾回收,但系統是否進行垃圾回收依然不能確定。大部分時候,程序強制垃圾回收後總是有一些效果。

強制系統垃圾回收有如下兩個方法:

調用System類的gc()靜態方法:System.gc()

調用Runtime對象的gc()實例方法:Runtime.getRuntime().gc()

強制垃圾回收代碼:

public class GcTest

{

public static void main(String[] args)

{

for (int i = 0 ; i < 1; i++)

{

new GcTest();

// 下面兩行代碼的作用完全相同,強制系統進行垃圾回收

// System.gc();

Runtime.getRuntime().gc();

}

}

public void finalize()

{

System.out.println("系統正在清理GcTest對象的資源...");

}

}

常見的GC算法有哪些?

標記-清除算法(Mark-Sweep)

最基礎的GC算法,將需要進行回收的對象做標記,之後掃描,有標記的進行回收,這樣就產生兩個步驟:標記和清除。這個算法效率不高,而且在清理完成後會產生內存碎片,這樣,如果有大對象需要連續的內存空間時,還需要進行碎片整理,所以,此算法需要改進。

複製算法(Copying)

前面我們談過,新生代內存分為了三份,Eden區和2塊Survivor區,一般Sun的JVM會將Eden區和Survivor區的比例調為8:1,保證有一塊Survivor區是空閒的,這樣,在垃圾回收的時候,將不需要進行回收的對象放在空閒的Survivor區,然後將Eden區和第一塊Survivor區進行完全清理,這樣有一個問題,就是如果第二塊Survivor區的空間不夠大怎麼辦?這個時候,就需要當Survivor區不夠用的時候,暫時借持久代的內存用一下。此算法適用於新生代。

標記-整理(或叫壓縮)算法(Mark-Compact)

和標記-清楚算法前半段一樣,只是在標記了不需要進行回收的對象後,將標記過的對象移動到一起,使得內存連續,這樣,只要將標記邊界以外的內存清理就行了。此算法適用於持久代。

由於篇幅限制,就先給大家分享這麼多關於Java垃圾回收機制的常見面試問題,如果你需要一些這方面的視頻教程,關注轉發並私信我“編程”即可獲取,希望對大家的面試有所幫助。


分享到:


相關文章: