2011-08-28 84 views
17

當我運行下面提到的代碼(使用netbeans)時,分配的堆大小以鋸齒形狀變化。我從jVisualVM附加捕獲,顯示鋸齒形狀中使用的堆圖。該程序是一個簡單的無限循環打印「大聲笑」n標準輸出。爲什麼鋸齒形圖?

class one{ 
    static int i=0; 
    public static void main(String a[]){ 
     while(i<10){ 
      System.out.println("lol"); 
     } 
    } 
} 

enter image description here 誰能解釋使用的堆的圖形的形狀背後的原因是什麼?

PS:此發生,即使我不使用NetBeans所以這是有點不相關的NetBeans的運行它...

+1

而且似乎有所不同...呃... 3兆字節?這真的可以嗎? – Owen

+0

您可以通過嘗試其他垃圾收集器算法來了解這一點。有關詳情,請參閱此處:http://www.tikalk.com/java/garbage-collection-serial-vs-parallel-vs-concurrent-mark-sweep – skaffman

+3

@ buch11:永遠不要低估巨大的垃圾量,即使是最平凡的Java方法/ API可以生成。我已經完成了使用Java的多線程科學計算,並且我可以告訴你有很多的問題,它甚至不好笑;)你必須認識到大多數Java程序員會很樂意使用諸如* Map *之類的東西並告訴你如果它不是瓶頸,那就沒有問題。 Java基本上是一個幾乎每個人都會產生無數浪費的世界,並且認爲:*「垃圾回收器會照顧它」*。有一個原因,爲什麼Photoshop不是用Java編寫的;) – SyntaxT3rr0r

回答

23

堆使用中的鋸齒模式可以通過在調用System.out.println調用期間創建幾個局部變量來解釋。最值得注意的是在甲骨文/ Sun JRE,幾個HeapCharBuffer實例在年輕一代創造,如下面的快照,注意使用的VisualVM的內存分析器獲得:

Visual VM - Memory snapshot

感興趣的是在數量存在於堆上的活動對象。鋸齒圖案源自伊甸園空間填滿時發生的年輕代垃圾收集週期;由於程序中沒有執行繁重的計算活動,因此JVM能夠執行循環的多次迭代,從而導致eden空間(4MB大小)填滿。接下來的年輕人收集週期清除掉大部分垃圾;它幾乎總是整個伊甸空間的,除非對象仍然在使用中,通過從VisualVM的獲得下述的GC痕量所示:

Visual VM GC probes

鋸齒圖案的行爲因此可以由解釋一系列快速連續的對象分配填滿了伊甸園空間,引發了一個年輕的垃圾收集週期;由於基礎JVM進程沒有被另一進程搶佔,並且負責對象分配的JVM中的主線程也不會被另一個線程搶佔,所以該進程循環重複,沒有延遲。

+0

明白了!!!謝謝。 – buch11

+0

不客氣。順便說一句,我沒有得到完美的鋸齒波,因爲我在VisualVM和Eclipse之間保持Alt-tab。另一方面,你的截圖表明你已經運行了很長一段時間了。 –

+0

實際上我正在編寫一些使用線程的東西,突然代碼進入了無限的廁所,我去JVisualVM檢查哪個線程正在運行/正在睡眠/等待,並且鋸齒出現在我面前,一次認爲它是與線程相關的東西,但後來嘗試運行上面的代碼,所有的謎題從那裏開始只......我的VisualVM一直在運行。 – buch11

1

有很多它可以從現身的地方,很可能取決於執行。至少以下是可能的(但都僅是猜測)

  • 某處流的System.out.println下方的堆有一個字節數組分配(給定的輸出流的基本方法中的一種是寫入(字節[] b,詮釋掉,INT LEN))

  • 它的開銷,使用您正在使用的監控軟件(我沒有用它)

  • 它的開銷在NetBeans VM最終顯示輸出

5

任何以常規速率分配對象的進程都會導致堆內存消耗量的穩步增加,然後在垃圾收集器收集不再使用的對象時產生即時丟棄,從而導致鋸齒形狀。

如果您想知道爲什麼您的java進程在寫入System.out時保留了分配內存,請記住其他線程(例如將當前內存統計信息提供給JVisualVM)可能是分配內存的線程。

1

其實jVisualVM導致額外的對象分配。 jVisualVM和jconsole正在使用Java Management Extensions。附加到正在運行的應用程序並請求JVM度量標準,以創建其他對象。 您可以通過添加到您的程序調用

Runtime.getRuntime().freeMemory() 

其報告空閒內存在JVM堆驗證這一點。它會通過運行代碼顯示[幾乎]沒有內存變化,但只要將jVisualVM連接到您的程序,您會看到內存使用量增加。