2013-09-26 41 views
3

在對谷歌代碼中發現了一些圖書館中,我遇到了這個UTIL方法:Java:可靠地調用GC?

public static void gc(){ 
    Object obj = new Object(); 
    WeakReference ref = new WeakReference<Object>(obj); 
    obj = null; 
    while(ref.get()!=null) 
    System.gc(); 
} 

其醫生說它提供了一種可靠的方法來調用GC,因爲調用系統#GC()僅僅是沒有任何保障的提示。我把它展示給了我的老大,他說我應該考慮爲什麼這種方法是無效的。 我讀了一些關於弱引用的文章,但我仍然感到困惑。 有人可以告訴我這一點嗎?

+11

專注於你的業務邏輯..其餘的java處理! :) – Anirudha

+1

我絕對同意:)我永遠不會依賴像「調用GC」的東西。我只是好奇。 – gyorgyabraham

+0

如果gc()只是一個提示,那麼沒有理由認爲GC會實際發生。你在這裏沒有做什麼真的讓gc發生(想想GC的用途是什麼...)?如果沒有真正發生,你的方法會做什麼? – Brabster

回答

7

我有直接的經驗,你所發佈的假設的「安全的GC」成語。

它不起作用。

原因很簡單:只是清除弱ref的事實是而不是收集到對象的信號;它只意味着它通過任何強或軟的參考變得無法達到。根據我的經驗,這個信號在物體被回收之前到達。

一個更好的嘗試是使用一個虛引用,這至少保證了對象已進入終結狀態,但再次,它仍然可以佔據堆,並在實踐中它仍然佔領它。另一種解釋可能是,這個顯然居住在伊甸園空間的特定對象確實得到了回收,但是GC的運行並不詳盡,在其他幾代人中還有更多的回憶。

在另一方面,我也非常可靠地使用這個簡單的成語:

for (int i = 0; i < 3; i++) { System.gc(); Thread.sleep(500); } 

試一試,看看它是否適合你。 sleep部分是可選的:只有在System.gc()使用併發掃描時才需要。

如果你反對這種方法的明顯浮躁,只要記住的任何方法顯式GC-ing是變幻莫測的。這至少是誠實的,只是碰巧在實際的系統上工作。它自然不可移植,並且由於各種各樣的原因,可能隨時停止工作。即便如此,這是你獲得的最好成績。

+0

同意,我想知道對象在與GC代碼相同的方法中聲明時對「對象強度」的影響是什麼。看起來像一個糟糕的計劃,試圖垃圾收集你剛剛宣佈4線的對象。可能會更好地儘快將所有提及的內容都去掉。 –

+0

@grep在OP的代碼中,對'obj'的引用確實被明確地清除了。 –

+0

弱refs只能由GC清除,這意味着只要GC變爲空,GC就確實運行。問題在於你試圖解決的問題「是否收集了物體」?與「GC是否至少運行一次?」不一樣?終結者和所有的.. – Voo

2

重點是,那System.gc()不需要清理所有弱引用。並考慮一些Java虛擬機。如果System.gc爲一次(第一次)確定爲而不是清除該引用,則很可能在下次調用。因此,您有一個可能無限循環。可能取決於其他線程更改垃圾收集的狀態以終止循環。

所以:一次就夠了。

+0

根據我的經驗,第二次電話幾乎總是能夠回收更多的記憶。可能是定稿週期。 –

+0

@MarkoTopolnik也有同樣的體驗(Oracle jvm)。雖然如果gc被實現爲_「如果當前狀態有足夠的空間返回」,那麼無界循環是愚蠢的。甚至Oracle的gc也有很多選擇。所以兩次做一個gc應該就足夠了。實際上,創建一個觸發垃圾回收的對象是不正當的。 –

+0

準確地說,我通常會使用兩個電話,有時候只需要添加三分之一就可以達到很好的效果。我有時會打印'totalMemory - freeMemory'來確認第三個沒有釋放任何內存。 –

1

沒有保證GC呼叫的方法,因爲正如文檔所述,System.gc只是系統可以忽略的提示。

因此,假設JVM忽略System.gc - 在這種情況下,整個事情只是循環,直到系統的其他部分導致GC。如果你運行單線程或者沒有其他人分配太多的內存,你基本上在這裏創建一個inifite循環。

0

問題是您的線程將停止並等待弱引用被清除,從而「模擬」垃圾回收。無法保證何時(甚至實際上)會發生這種情況。

您可能會長時間滯留在此while上等待。

+0

,如果我們把它放在一個線程? – Cruncher

+0

它阻止,你要麼永遠等待,要麼手動殺死它。我以爲這就是我剛纔所說的? – blgt

0

我同意你應該專注於業務邏輯,但我覺得它是一個interssting實現,我認爲它應該工作 - 理論上。

儘管如此,代碼的問題在於,您在循環中等待收集的引用進行收集 - 一直忙於等待垃圾收集器移除對象,因爲它只是weakly reachable

System.gc()只是一個提示。所以這個方法可能會永遠等待。

目前我沒有看到必要的用例。

爲什麼應用程序顯式等待直到垃圾收集器運行?

0

編程我們需要確保,當一個obj被刪除,那麼它的相應條目應該被刪除。只有這樣,該對象纔會成爲垃圾收集的候選對象。否則,即使它在運行時沒有被使用,這個陳舊的對象也不會被垃圾收集。

該引用引用的對象,如果該引用對象已被清除,則返回null。 作爲WeakReference類的對象引用。所以它不會給null。但是在刪除gc之後,它提供了null。

Object obj = new Object(); 
     WeakReference ref = new WeakReference<Object>(obj); 
     obj = null; 
     if(ref.get()!=null) 
     { 
      System.gc(); 
      System.out.println("remove ref"); 
     } 
     if(ref.get()!=null){ 
      System.out.println("not execute"); 
     } 

輸出:

remove ref 

不要指定空值設置爲obj。

Object obj = new Object(); 
     WeakReference ref = new WeakReference<Object>(obj); 
     if(ref.get()!=null) 
     { 
      System.gc(); 
      System.out.println("remove ref"); 
     } 
     if(ref.get()!=null){ 
      System.out.println("execute"); 
     } 

輸出:

remove ref 
execute 
0

代碼,試圖迫使GC通常是一個潛在的更大的問題的跡象(即設計問題或對部分開發商缺少知識)。

我已經看到了一些使用情況,其中在生產代碼中調用System.gc()實際上是有意義的,例如,在打印當前的內存使用情況之前 - 值是否關閉並不重要,但我們希望提高值儘可能小。當然,我們知道GC已啓用 - 我們用它來自動檢測QA系統上的內存泄漏。

一般來說,打電話System.gc()大叫「我的代碼是越野車,我不知道如何解決它!」。