2012-04-11 44 views
26

我還在學習Java的繩索,所以很抱歉,如果有明顯的答案。我有一個需要大量內存的程序,我想找出一種方法來減少它的使用,但是在閱讀了很多SO問題之後,我有一個想法,那就是在開始優化之前需要證明問題出在哪裏。如何在Java中存儲配置文件?

這就是我所做的,我在程序的開始處添加了一箇中斷點並運行它,然後我啓動了visualVM並對其進行了配置文件(我也在netbeans中做了同樣的事情來比較結果和他們是一樣的)。我的問題是我不知道如何閱讀,我得到的最高區域只是說char[],我看不到任何代碼或任何東西(這是有道理的,因爲visualvm連接到jvm,看不到我的源,但netbeans也不會像我在做cpu分析時那樣給我看源代碼)。

基本上我想知道的是所有內存正在被使用的變量(希望更多的細節在哪個方法中),所以我可以專注於在那裏工作。有沒有簡單的方法來做到這一點?我現在正在使用eclipse和java來開發(並且安裝專門用於分析的visualVM和netbeans,但願意安裝任何你覺得完成這項工作的東西)。

編輯:理想情況下,我正在尋找的東西,將採取我所有的對象和按大小排序(所以我可以看到哪一個是佔用內存)。目前它返回的信息,如字符串[]或int [],但我想知道它指的是哪個對象,所以我可以使其尺寸更優化。

+0

我使用了一個分析器,它可以顯示我分配對象的位置。我不知道VisualVM是否可以做到這一點,但它非常有用。我使用的是YourKit,但它不是免費的(但你可以獲得一個eval許可證) – 2012-04-11 15:31:40

+0

@PeterLawrey我實際上閱讀了你前面寫過的一個答案,你提到yourkit是你的第一選擇,我確實查了它(因爲你的建議總是很棒),但是它有點貴,我只是在學習。 – 2012-04-11 15:33:50

+0

沒有使用儀器代碼的東西沒有分析儀將能夠指出哪個實例==你稱爲你的來源參考。 – 2012-04-11 16:05:04

回答

22

字符串是有問題的

基本上在Java中,String引用(使用char[]幕後的東西)將智慧主宰最業務應用程序的內存。它們的創建方式決定了它們在JVM中佔用的內存量。

僅僅因爲它們對於大多數業務應用程序來說如同數據類型一樣非常重要,並且它們也是最需要內存的之一。這不僅僅是一個Java事物,String數據類型在幾乎每種語言和運行時庫中佔用大量內存,因爲至少它們只是每個字符1個字節的數組,或者更糟糕的是(Unicode),它們是數組每個字符多個字節。

一旦紋上的Web應用程序,也有一個Oracle JDBC的依賴CPU的使用率,當我發現StringBuffer.append()由多個數量級的占主導地位的CPU週期比所有其他方法調用結合,更不用說其他任何單一的方法調用。 JDBC驅動程序做了大量的操作,使用PreparedStatements來處理所有事情。

你是什麼人關心你無法控制,不能直接反正

你應該專注於什麼是什麼在你的控制,這是確保你不抱上引用長於你需要,而且你沒有不必要的重複。 Java中的垃圾收集例程經過高度優化,如果您瞭解它們的算法如何工作,則可以確保您的程序以最佳方式運行這些算法。

Java堆內存不喜歡手動管理存儲在其他語言中,這些規則並不適用

什麼被認爲內存泄漏其他語言是不一樣的東西/根源爲用Java的垃圾收集系統。

最有可能在Java內存中沒有被泄漏的單個超級對象(其他環境中的懸掛參考)佔用。

這是最有可能的,因爲很多StringBuffer/StringBuilder對象不是第一instantantations適當大小,然後不得不自動增長char[]陣列舉行後續append()通話較小的分配的。

由於垃圾收集器的範圍和許多其他事情在運行時可能會有所不同,因此這些中間對象可能比垃圾收集器預期的時間長。

示例:垃圾收集器可能會決定有候選人,但由於它認爲仍有大量內存需要處理,因此在該時間點刷新它們可能太昂貴了,它會一直等到內存壓力升高。

垃圾收集器現在真的很好,但它不是魔術,如果你正在做退化的事情,它會導致它不能最佳工作。互聯網上有大量關於所有JVM版本的垃圾收集器設置的文檔。

這些未引用的對象可能尚未達到垃圾回收器認爲需要它們從內存中清除它們的時間,或者可能存在其他對象(例如List)所引用的引用你沒有意識到仍然指向那個對象。這在Java中最常被稱爲泄漏,這是更具體的參考泄漏。

例:如果你知道你需要使用StringBuildernew StringBuilder(4096);不是默認的,這就好比32,並立即開始創建的垃圾,可以代表很多時候你在想什麼對象應該創造它來建立一個4K String在尺寸上明智。

你可以發現有多少類型的對象用VisualVM實例化,這會告訴你你需要知道什麼。不會有閃光燈指向一個類的單個實例,即「這是大內存消費者!」,即除非您正在閱讀的某個char[]只有一個實例大量的文件到,這也是不可能的,因爲很多其他類在內部使用char[];然後你幾乎已經知道了。

我沒有看到OutOfMemoryError

任何提及,你可能沒有在你的代碼中的問題,垃圾收集系統,只是可能沒有得到足夠的壓力下踢在和釋放放置物體你認爲它應該清理。什麼你認爲是一個問題可能不是,除非你的程序崩潰與OutOfMemoryError。這不是C,C++,Objective-C或任何其他手動內存管理語言/運行庫。你不能決定什麼是在記憶中,或者不在你所期待的細節層面上。

0

如果使用visualVM檢查內存使用情況,它將重點放在數據上,而不是方法。也許你的大char []數據是由許多String值引起的?除非使用遞歸,否則數據將不會來自本地變量。因此,您可以專注於將元素插入大數據結構的方法。要了解精確的語句將導致你的「內存泄露」,我建議你另外

2

我會建議捕獲堆轉儲和使用像Eclipse MAT這樣的工具,讓你分析它們。有很多tutorials可用。它提供dominator tree的視圖,以深入瞭解堆上對象之間的關係。特別是對於你所提到的,MAT的「GC根源路徑」功能將告訴你哪些大部分char [],String []和int []對象被引用。 JVisualVM還可以用於識別泄漏和分配,特別是通過使用分配堆棧跟蹤的快照。有很多walk-throughs of the process獲取快照並比較它們以找到分配點。

7

JProfiler中,您可以轉到堆步行者並激活最大的對象視圖。你會看到對象保留大部分內存。如果您刪除了對象,「保留」內存是垃圾回收器將釋放的內存。

然後,您可以打開對象節點以查看保留對象的引用樹。這裏是最大的對象視圖的屏幕截圖:

enter image description here

免責聲明:我公司開發的JProfiler

相關問題