java finalize 方法引發的記憶體泄露

來源:互聯網
上載者:User
java finalize 方法引發的記憶體泄露 Posted: Mon, 11 Mar 2013 java 記憶體dump

記憶體dump後,大量的記憶體(>5G) 被 java.lang.ref.Finalizer hold 住(見圖1)。 而這些記憶體是BDB佔用,懷疑是BDB有記憶體泄露(見圖2)。 java finalizer 機制

為什麼會是 java.lang.ref.Finalizer 的引用導致BDB無法釋放記憶體。沒有開啟即時索引的機器上BDB不會有記憶體泄露?重新瞭解java finalize的機制:

實現了finalize的對象,建立和回收的過程都更耗時。建立時,會建立一個額外的Finalizer 對象指向新建立的對象。 而回收時,至少需要經過兩次GC. 第一次GC, 檢測到對象只有被Finalizer引用,將這個對象放入 java.lang.ref.Finalizer.ReferenceQueue 此時,因為Finalizer的引用,對象還無法被GC. java.lang.ref.Finalizer$FinalizerThread 會不停的清理Queue的對象,remove掉當前元素,並執行對象的finalize方法。 清理後,對象沒有任何引用,在下一次GC被回收。

finalizer 定位

最後我們發現 java.lang.ref.Finalizer$FinalizerThread wait在一個即時索引的線程上, 見下面代碼.

//   java多線程同步的一種典型實現:   //  迴圈檢查條件(cachedreaderTimestamp <= begintime), 每次wait一小段時間(200ms),最多wait指定的時間(timeout)   //  另外一個線程會修改條件,讓條件為true (cachedreaderTimestamp > begintime)   while (cachedreaderTimestamp <= begintime)   {           synchronized (cachemonitor)               {                    cachemonitor.notifyAll();                   long elapsed = System.currentTimeMillis() - begintime;                   if (elapsed > timeout) // elapsed 有可能等於 timeout               {                             log.debug("refreshCached reader timeout in " + elapsed + "ms");                             throw new ZoieException("refreshCached reader timeout in " + elapsed + "ms");               }                   long timetowait = Math.min(timeout - elapsed, 200);           try           {                 cachemonitor.wait(timetowait); //要麼被其他線程喚醒,要麼等待timetowait;如果timetowait為0時,只能被 其他線程喚醒,否則一直等待           }    catch (InterruptedException e)           {                 log.warn("refreshCache", e);           }   }   
code review

檢查mandy中的代碼發現,有個shutdown 方法被調用兩次一次顯示調用,一次是finalize中調用第一次調用時,執行上面的代碼即便timetowait為0,也沒問題,會有線程喚醒調用者; 隨後喚醒線程也退出.第二次finalize線程調用時,執行上面的代碼timetowait為0時,調用線程(finalize線程)會一直block。因為喚醒線程在第一 次調用時已經退出. fix

去掉finalize 方法即可 replay

執行下面的程式java -Xmx100m Finalize 程式永不停止

public class Finalize {          byte[] a = new byte[10 * 1024 * 1024 ];             protected void _finalize() {                   synchronized(this) {                           try {                                   this.wait(0);                           } catch(Exception e) {                                   System.err.println(e);                           }                   }          }             public static void main(String[] args) throws Exception {                   while(true) {                           new Finalize();                           Thread.sleep(200);                   }          }   }   

修改後,實現 finalize 方法java -Xmx100m Finalize

很快報記憶體溢出錯誤Exception in thread “main” java.lang.OutOfMemoryError: Java heap space

protected void _finalize() {                   synchronized(this) {                           try {                                   this.wait(0);                           } catch(Exception e) {                                   System.err.println(e);                           }                   }          }      --->      protected void finalize() {                   synchronized(this) {                           try {                                   this.wait(0);                           } catch(Exception e) {                                   System.err.println(e);                           }                   }          }   

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.