2009-02-17 90 views
6

以下是我需要解決的情況。我有兩個解決方案。在Java中查找內存使用情況

我需要維護從數據庫中獲取的數據的緩存,以便在Swing GUI上顯示。 每當我的JVM內存超過其分配內存的70%時,我需要警告用戶過度使用。一旦JVM內存使用率超過80%,那麼我必須停止所有的數據庫查詢並清理作爲用戶操作一部分獲取的現有緩存並通知用戶。在清理過程中,我將手動處理刪除某些基於某些規則的數據並指示JVM進行GC。每當GC發生時,如果內存清理並達到分配內存的60%,則需要重新啓動所有數據庫處理並將控制權交還給用戶。

爲了檢查JVM內存統計信息,我找到了以下兩種解決方案。無法確定哪個是最好的方式以及爲什麼。

  1. Runtime.freeMemory() - 創建線程運行每10秒並檢查可用內存,如果內存超過提到的限制,必要的彈出窗口將親密用戶並調用方法來制止的操作和釋放記憶。

  2. MemoryPoolMXBean.getUsage() - Java 5引入了JMX以在運行時獲取內存快照。在,JMX我不能使用閾值通知,因爲它只會在內存達到/超過給定的閾值時通知。唯一使用的方法是在MemoryMXBean中輪詢並檢查一段時間內的內存統計信息。

在使用輪詢的情況下,對我來說這兩種實現看起來都是一樣的。

請建議的方法的優點,如果有任何其他替代品/方法使用的任何更正。

回答

2

我只使用第一種方法進行類似的任務,它是確定的。

對於這兩種方法,你應該注意的一件事是實施某種類型的反彈 - 即一旦你認識到你已經擊中了70%的內存,等待一分鐘(或任何其他時間,你覺得合適) - GC可以在那個時候運行並清理大量的內存。

如果你在你的系統中實現了一個Runtime.freeMemory()圖形,你將會看到內存是如何不斷地向上和向下,向上和向下。

5

JVM的內存使用率達到100%並且在GC之後回到10%是完全正常的,並且每隔幾秒就會這樣做。

您不應該嘗試以這種方式管理內存。 在完整的GC運行之前,您不能說保留了多少內存。

我建議你研究一下你真正努力實現的目標,並以另一種方式來看問題。

+0

IMO,這並不完全正常。這些參數可以調整(池大小,完整的GC間隔等) – 2009-02-17 07:36:51

14

只是旁註:Runtime.freeMemory()沒有說明剩餘內存的分配量,它只是當前分配內存中的空閒內存量(它最初小於VM配置的最大內存量使用),但會隨着時間而增長。

啓動虛擬機時,最大內存(Runtime.maxMemory())僅定義了虛擬機可以分配的內存上限(可使用-Xmx VM選項配置)。 總內存(Runtime.totalMemory())是爲VM進程分配的內存的初始大小(可使用-Xms VM選項進行配置),並且每次分配多於當前空閒部分(Runtime.freeMemory())時會動態增長,直到它達到最大內存。

你感興趣的指標可用於進一步分配內存:

long usableFreeMemory= Runtime.getRuntime().maxMemory() 
    -Runtime.getRuntime().totalMemory() 
    +Runtime.getRuntime().freeMemory() 

或:

double usedPercent=(double)(Runtime.getRuntime().totalMemory() 
    -Runtime.getRuntime().freeMemory())/Runtime.getRuntime().maxMemory() 
4

你提到與垃圾收集的是如何工作的一個明顯的矛盾的要求JVM。

由於JVM的行爲,很難以正確的方式警告用戶。 完全停止als數據庫操作,清理東西並重新開始真的不是要走的路。

讓JVM做它應該做的事,處理與您相關的所有內存。 JVM的現代幾代人都非常好它,並用GC參數的一些細化和微調,您將得到AA乾淨得多的內存處理,然後強迫的事情自己

文章像http://www.kodewerk.com/advice_on_jvm_heap_tuning_dont_touch_that_dial.htm提的利弊,並提供了一個很好的解釋了什麼虛擬機爲你服務

0

調查JConsole。它繪製了您需要的信息,因此可以根據您的需要調整這些信息(假設您在Sun Java 6上運行)。

這也可以讓你從你想看的東西中分離出監視過程。

7

處理這類事情的通常方法是使用WeakReference s和SoftReference s。你需要同時使用 - 弱引用意味着你沒有持有多個副本,軟引用意味着GC將掛起東西,直到它開始用完內存。

如果您需要執行額外的清理,那麼您可以添加對隊列的引用,並覆蓋隊列通知方法以觸發清理。這很有趣,但你需要了解這些課程的作用。

1

VisualVM比JConsole好一點,因爲它給你一個很好的視覺垃圾收集器視圖。

0

在原帖之後很晚,我知道,但我想我會發表一個我如何完成它的例子。希望對某人有用處(我強調,這是一個主要的例子,沒有其他的東西......也不是特別優雅:))

只需將這兩個函數粘在一個類中,它應該可以工作。

編輯:哦,import java.util.ArrayList; import java.util.List;

public static int MEM(){ 
    return (int)(Runtime.getRuntime().maxMemory()-Runtime.getRuntime().totalMemory() +Runtime.getRuntime().freeMemory())/1024/1024; 
} 

public static void main(String[] args) throws InterruptedException 
{ 
    List list = new ArrayList(); 

    //get available memory before filling list 
    int initMem = MEM(); 
    int lowMemWarning = (int) (initMem * 0.2); 
    int highMem = (int) (initMem *0.8); 


    int iteration =0; 
    while(true) 
    { 
     //use up some memory 
     list.add(Math.random()); 

     //report 
     if(++iteration%10000==0) 
     { 
      System.out.printf("Available Memory: %dMb \tListSize: %d\n", MEM(),list.size()); 

      //if low on memory, clear list and await garbage collection before continuing 
      if(MEM()<lowMemWarning) 
      { 
       System.out.printf("Warning! Low memory (%dMb remaining). Clearing list and cleaning up.\n",MEM()); 

       //clear list 
       list = new ArrayList(); //obviously, here is a good place to put your warning logic 

       //ensure garbage collection occurs before continuing to re-add to list, to avoid immediately entering this block again 
       while(MEM()<highMem) 
       { 
        System.out.printf("Awaiting gc...(%dMb remaining)\n",MEM()); 
        //give it a nudge 
        Runtime.getRuntime().gc(); 
        Thread.sleep(250); 
       } 

       System.out.printf("gc successful! Continuing to fill list (%dMb remaining). List size: %d\n",MEM(),list.size()); 
       Thread.sleep(3000); //just to view output 
      } 
     } 
    } 
} 

編輯:此方法仍然依賴於使用-Xmx JVM的內存設置合理不過。

編輯2:似乎gc請求行真的幫助一些事情,至少在我的jvm。因人而異。