亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

監控Java應用程序Windows內存使用情況

系統 1743 0
盡管 Java? 運行時能夠解決大量的內存管理問題,但對程序的內存占用情況保持警惕仍然是優化機器性能、測定內存泄露的關鍵。Windows 上有很多工具可以監控內存的使用。但每種工具各有長短,都有特定的傾向性,常常沒有明確地定義自己測量的是什么。作者將澄清關于內存使用的一些常見誤解, 介紹很多有用的工具,同時還將提供何時以及如何使用它們的指南。
<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --> <!--END RESERVED FOR FUTURE USE INCLUDE FILES-->

Java 技術最知名的一個優點是:與其他語言如 C 程序員不同,Java 程序員不需要對令人畏懼的內存分配和釋放負責。Java 運行庫可以為您管理這些任務。每個實例化的對象都自動在堆中分配內存,垃圾收集程序定期收回不再使用的對象所占據的內存。但是您還不能完全撒手不管。您仍 然需要監控程序的內存使用情況,因為 Java 進程的內存不僅僅包括堆中分配的對象。它還包括程序的字節碼(JVM 在運行時解釋執行的指令)、JIT 代碼(已經為目標處理器編譯過的代碼)、任何本機代碼和 JVM 使用的一些元數據(異常表、行號表等等)。情況更為復雜的是,某些類型的內存(如本機庫)可以在進程間共享,因此確定 Java 應用程序的內存占用可能是一項非常艱巨的任務。

有大量在 Windows 監控內存使用的工具,但不幸的是沒有一種能夠提供您需要的所有信息。更糟的是,這些形形色色的工具甚至沒有一個公共的詞匯表。但本文會助您一臂之力,文中將介紹一些最有用的、可免費獲得的工具,并提供了如何使用它們的技巧。

Windows 內存:一次旋風般的旅行

了解本文要討論的工具之前,需要對 Windows 如何管理內存有基本的理解。Windows 使用一種 分頁請求虛擬內存 系統,現在我們就來分析一下這種系統。

虛擬地址空間

虛擬內存的概念在上個世紀五十年代就提出了,當時是作為解決不能一次裝入實際內存的程序這一復雜問題的方案提出的。在虛擬內存系統中,程序可以訪問超出可用物理內存的更大的地址集合,專用內存管理程序將這些邏輯地址映射到實際地址,使用磁盤上的臨時存儲保存超出的部分。

Windows 所使用的現代虛擬內存實現中,虛擬存儲被組織成大小相同的單位,稱為 。每個操作系統進程占用自己的 虛擬地址空間 ,即一組可以讀寫的虛擬內存頁。每個頁可以有三種狀態:

  • 自由 :還沒有進程使用這部分地址空間。如果企圖訪問這部分空間,無論讀寫都會造成某種運行時失效。該操作將導致彈出一個 Windows 對話框,提示出現了訪問沖突。(Java 程序不會造成這種錯誤,只有用支持指針的語言編寫的程序才可能造成這種問題。)

  • 保留 :這部分地址空間保留給進程,以供將來使用,但是在交付之前,不能訪問該地址空間。很多 Java 堆在一開始處于保留狀態。

  • 提交 :程序可以訪問的內存,得到了完全 支持 ,就是說已經在分頁文件中分配了頁幀。提交的頁只有在第一次被引用時才裝入主存,因此成為 請求式分頁

圖 1 說明了進程地址空間中的虛擬頁如何映射到內存中的物理頁幀。


圖 1. 進程地址空間中的虛擬頁到物理頁幀的映射
內存組織

如 果運行的是 32 位機器(如一般的 Intel 處理器),那么進程的整個虛擬地址空間就是 4GB,因為這是用 32 位所能尋址的最大地址空間。Windows 通常不會允許您訪問地址空間中的所有這些內存,進程自己使用的只有不到一半,其他供 Windows 使用。這 2 GB 的私有空間部分包含了 JVM 執行程序所需要的多數內存:Java 堆、JVM 本身的 C 堆、用于程序線程的棧、保存字節碼和即時編譯方法的內存、本機方法所分配的內存等等。后面介紹地址空間映射時,我們將描述這些不同的部分。

希望分配了大量連續內存區域但這些內存不馬上同時使用的程序常常結合使用保留內存和提交內存。JVM 以這種方式分配 Java 堆。參數 -mx 告訴 JVM 堆有多大,但 JVM 通常不在一開始就分配所有這些內存。它 保留 -mx 所規定的大小,標記能夠提交的整個地址范圍。然后它僅僅提交一部分內存,這也是內存管理程序需要在實際內存和分頁文件中分配頁來支持它們的那一部分。以后 活動數據數量增加,堆需要擴展,JVM 可以再提交多一點內存,這些內存與當前提交的部分相鄰。通過這種方式,JVM 可以維護單一的、連續的堆空間,并根據需要增長(關于如何使用 JVM 堆參數請參閱 參考資料 )。

實際內存

物理存儲頁組織成大小相同的單位,通常稱為 頁幀 。操作系統有一種數據結構稱為 頁表 ,將應用程序訪問的虛擬頁映射到主存中的實際頁幀。沒有裝入的頁保存在磁盤上的臨時分頁文件中。當應用程序要訪問當前不在內存中的頁時,就會出現 頁面錯誤 ,導致內存管理程序從分頁文件中檢索該頁并放到主存中,這個任務稱為 分頁 。 決定將哪些頁交換出去的具體算法取決于所用的 Windows 版本,可能是最近最少訪問算法的一種變體。同樣要注意,Windows 允許進程間共享頁幀,比如 DLL 分配的頁幀,常常被多個應用程序同時使用。Windows 通過將來自不同地址空間的多個虛擬頁映射到同一個物理地址來實現這種機制。

應用程序很高興對所有這些活動一無所知。它只知道自己的虛擬地址空間。但是,如果當前在主存中的頁面集(稱為 駐留集 )少于實際要使用的頁面集(稱為 工作集 ),應用程序的性能很快就會顯著降低。(不幸的是,本文中您將看到,我們要討論的工具常常交換使用這兩個術語,盡管它們指的是完全不同的事物。)







Task Manager 和 PerfMon

我們首先考察兩種最常見的工具:Task Manager 和 PerfMon。這兩個工具都隨 Windows 一起提供,因此由此起步比較容易。

Task Manager

Task Manager 是一種非常見的 Windows 進程監控程序。您可以通過熟悉的 Ctrl-Alt-Delete 組合鍵來啟動它,或者右擊任務欄。Processes 選項卡顯示了最詳細的信息,如圖 2 所示。


圖 2. Task Manager 進程選項卡
TaskManager

圖 2 中顯示的列已經通過選擇 View --> Select Columns 作了調整。有些列標題非常含糊,但可以在 Task Manager 幫助中找到各列的定義。和進程內存使用情況關系最密切的計數器包括:

  • Mem Usage(內存使用) :在線幫助將其稱為進程的工作集(盡管很多人稱之為駐留集)——當前在主存中的頁面集。但是這個數值包含能夠和其他進程共享的頁面,因此要注意避免重復計算。比方說,如果要計算共享同一個 DLL 的兩個進程的總內存占用情況,不能簡單地把“內存使用”值相加。

  • Peak Mem Usage(內存使用高峰值) :進程啟動以來 Mem Usage(內存使用)字段的最大值。

  • Page Faults(頁面錯誤) :進程啟動以來要訪問的頁面不在主存中的總次數。

  • VM Size(虛擬內存大小) :聯機幫助將其稱為“分配給進程私有虛擬內存總數。”更確切地說,這是進程所 提交 的內存。如果進程保留內存而沒有提交,那么該值就與總地址空間的大小有很大的差別。

雖然 Windows 文檔將 Mem Usage(內存使用)稱為工作集,但在該上下文中,它實際上指的是很多人所說的駐留集(resident set),明白這一點很重要。您可以在 Memory Management Reference 術語表(請參閱 參考資料 )中找到這些術語的定義。 工作集 更通常的含義指的是一個邏輯概念,即在某一點上為了避免分頁操作,進程需要駐留在內存中的那些頁面。

PerfMon

隨 Windows 一起提供的另一種 Microsoft 工具是 PerfMon,它監控各種各樣的計數器,從打印隊列到電話。PerfMon 通常在系統路徑中,因此可以在命令行中輸入 perfmon 來啟動它。這個工具的優點是以圖形化的方式顯示計數器,很容易看到計數器隨時間的變化情況。

請在 PerfMon 窗口上方的工具欄中單擊 + 按鈕,這樣會打開一個對話框讓您選擇要監控的計數器,如圖 3a 所示。計數器按照 性能對象 分成不同的類別。與內存使用關系最密切的兩個類是 Memory Process 。選中計數器然后單擊 Explain 按鈕,就可以看到計數器的定義。說明出現在主對話框下方彈出的單獨的窗口中,如圖 3b 所示。


圖 3a. PerfMon 計數器窗口
PerfMon 計數器窗口

圖 3b. 說明
PerfMon 說明窗口

選擇感興趣的計數器(使用 Ctrl 可以選中多行)和要監控的實例(所分析的應用程序的 Java 進程),然后單擊 Add 按鈕。工具立刻開始顯示選擇的所有計數器的值。您可以選擇用報告、圖表或者直方圖來顯示這些值。圖 4 顯示的是一個直方圖。


圖 4. PerfMon 直方圖
PerfMon 直方圖

如果圖中什么也看不到,表明您可能需要改變比例,右擊圖形區域,選擇 Properties 然后切換到 Graph 選項卡。也可以到計數器的 Data 選項卡改變某個計數器的比例。

要觀察的計數器
不幸的是,PerfMon 使用了與 Task Manager 不同的術語。表 1 列出了最常用的計數器,如果有的話,還給出了相應的 Task Manager 功能:


表 1. 常用的 PerfMon 內存計數器
計數器名 類別 說明 等價的 Task Manager 功能
Working Set Process 駐留集,當前在實際內存中有多少頁面 Mem Usage
Private Bytes Process 分配的私有虛擬內存總數,即提交的內存 VM Size
Virtual Bytes Process 虛擬地址空間的總體大小,包括共享頁面。因為包含保留的內存,可能比前兩個值大很多 --
Page Faults / sec(每秒鐘內的頁面錯誤數) Process(進程) 每秒中出現的平均頁面錯誤數 鏈接到 Page Faults(頁面錯誤),顯示頁面錯誤總數
Committed Bytes(提交的字節數) Memory(內存) “提交”狀態的虛擬內存總字節數 --

嘗試一個例子

您可以下載并運行我們用 C 編寫的一個小程序(請參閱 下載 部分),來觀察 Task Manager 和 PerfMon 中顯示的這些數量。該程序首先調用 Windows VirtualAlloc 保留內存,然后再提交這些內存,最后使用其中一些內存,每 4,096 個字節寫入一個值,從而將頁面代入工作集。如果運行該例子,并使用 Task Manager 或 PerfMon 觀察,就會發現這些值的變化情況。







網絡上的有用工具

現在已經看到了應用程序使用多少內存,還需要深入分析內存的實際內容。這一節介紹一些更加復雜的工具,討論什么時候適用輸出結果,以及如何解釋這些結果。

PrcView

PrcView 是我們要介紹的第一個可以觀察進程地址空間內容的工具(請參閱 參考資料 )。該工具不僅能用于觀察內存占用,還可以設置優先級和殺死進程,還有一個很有用的命令行版本,用來列出機器上所有進程的屬性。但我們要介紹的如何使用它觀察內存占用情況。

啟動 PrcView 會看到一個類 Task Manager 的視圖,它顯示了系統中的進程。如果滾動窗口并選中一個 Java 進程,屏幕就會如圖 5 所示。


圖 5. 啟動后的 PrcView 窗口
PrcView 進程查看器

右擊該 Java 進程打開彈出菜單,或者從上方的菜單條中選擇 Process ,就可以看到該進程的一些情況,比如它擁有的線程、加載的 DLL,也可以殺死該進程或者設置其優先級。我們所關心的是考察其內存占用,打開如圖 6 所示的窗口。


圖 6. 觀察進程的內存
PrcView 內存 1

現 在我們分析一下 PrcView 顯示的地址空間映射的前幾行。第一行表明從地址 0 開始,有一塊長度為 65,536 (64K) 的內存是自由空間。這些地址什么也沒有分配,也不能用于尋址。第二行說明緊跟在后面,從地址 0x00010000 起,有一個長為 8,192 字節(兩個 4K 頁面)的提交內存,即可以尋址并且得到分頁文件中的頁幀支持的內存。然后是一段自由空間,另一段提交空間,如此等等。

碰巧的是,這些地址空間區域對您來說沒有什么意義,因為它是供 Windows 使用的。描述 Windows 地址空間的 Microsoft 文檔指出,這些不同的區域是為兼容 MS-DOS 保留的用戶數據和代碼所用的區域從 4MB 開始(請參閱 參考資料 )。

向下滾動窗口,最終會看到某些您能夠清楚識別的地址空間,如圖 7 所示。


圖 7. Java 堆
PrcView 內存 2

圖 7 中高亮顯示的行及其后的一行對應 Java 堆。我們給這里啟動的 Java 進程 1000MB 大小的堆(使用 -mx1000m ), 對于該程序而言,這個堆太大了,但這樣在 PrcView 映射中更加清楚。高亮顯示的一行說明堆的提交部分只有 4MB,從地址 0x10180000 開始。緊隨在后面的一行顯示了一個很大的保留區域,這是堆中還沒有提交的那一部分。在啟動過程中,JVM 首先保留出完整的 1000MB 空間(從 0x10180000 到 0x4e980000 范圍之內的地址都不能用),然后提交啟動過程所需要的那一部分,該例中為 4MB。為了驗證該值確實對應當前的堆大小,您可以用 -verbosegc JVM 選項調用該 Java 程序,可以打印出垃圾收集程序中的詳細信息。從下面的 -verbosegc 輸出中第二個 GC 的第二行可以看出,當前的堆大小大約是 4MB:

            >java -mx1000m -verbosegc Hello
            
[ JVMST080: verbosegc is enabled ]
[ JVMST082: -verbose:gc output will be written to stderr ]
<GC[0]: Expanded System Heap by 65536 bytes
<GC(1): GC cycle started Wed Sep 29 16:55:44 2004
<GC(1): freed 417928 bytes, 72% free (3057160/4192768), in 104 ms>
<GC(1): mark: 2 ms, sweep: 0 ms, compact: 102 ms>
<GC(1): refs: soft 0 (age >= 32), weak 0, final 2, phantom 0>
<GC(1): moved 8205 objects, 642080 bytes, reason=4>

-verbosegc 的輸出格式取決于所用的 JVM 實現,請參閱 參考資料 中關于 IBM JVM 的相關文章,或者參考供應商的文檔。

如果活動數據的數量增加,JVM 需要將堆的大小擴展到 4MB 之外,它就會提交稍微多一點的保留區域。就是說,新的區域可以從 0x10580000 開始,與已經提交的堆空間連接在一起。

圖 7 所示的 PrcView 窗口中,最下面一行的三個總數給出了進程提交的總內存,這些數據是根據第七列 Type 計算得到的。三個總數為:

  • Private :分頁文件支持的提交內存。
  • Mapped :直接映射到文件系統的提交內存。
  • Image :屬于可執行代碼的提交內存,包括啟動的執行文件和 DLL。

到目前為止,我們只是在根據大小來了解堆在地址空間中的分配情況。為了更好的理解其他一些內存區域,如果能夠觀察內存的內部情形,會對您的了解很有幫助。這就要用到下面將討論的工具 TopToBottom。

TopToBottom

TopToBottom 可以從 smidgeonsoft.com 免費獲得(請參閱 參考資料 )。該工具沒有任何文檔,但是為當前執行進程提供了一組完備的視圖。您不僅能夠按名稱進程 ID 排序,還能夠按起動時間排序,如果需要了解計算機上程序的啟動順序這一點可能很有用。

圖 8 所示的 TopToBottom 窗口中,進程是按創建時間排序的( View --> Sort --> Creation Time )。


圖 8. TopToBottom,進程按創建時間排序
TopToBottom 啟動窗口

StartUp 選項卡顯示了創建 Java 進程的進程、開始的時間和日期、所用的命令行以及可執行文件和當前目錄的完整路徑。也可以單擊 Environment 選項卡顯示啟動時傳遞給該進程的所有環境變量的值。Modules 選項卡顯示了 Java 進程所用的 DLL,如圖 9 所示。


圖 9. TopToBottom Modules 選項卡
TopToBottom 模塊

同 樣可以按照不同的方式對列表進行排序。在圖 9 中,它們是按照初始化順序排列的。如果雙擊其中的一行,可以看到 DLL 的詳細信息:其地址和大小、編寫的日期和時間、所依賴的其他 DLL 列表以及加載該 DLL 的所有運行中的進程列表。如果研究這個列表,就會發現有的 DLL 是每個運行的進程都要用到的,比如 NTDLL.DLL;有的在所有 Java 進程間共享,比如 JVM.DLL;而另有一些可能只有一個進程使用。

通過累加各個 DLL 的大小就可以計算出進程所用 DLL 的總大小。但是得到的結果可能會造成誤解,因為它并不意味著進程要消費所有這些內存占用。真正的大小取決于進程實際使用了 DLL 的哪些部分。這些部分將進入進程的工作集。雖然很明顯,但還是要注意 DLL 是只讀的和共享的。如果大量進程都使用一個給定的 DLL,同一時刻只有一組實際內存頁保存 DLL 數據。這些實際的頁面可以映射到不同的地址,進入使用它們的那些進程。Task Manager 之類的工具將工作集看作是共享和非共享頁面的總和,因此很難確定使用 DLL 對內存占用的影響。模塊信息是一種很有用的方式,提供了“最差情況下”由于 DLL 造成的內存占用,需要的話可以使用其他工具作更詳盡地分析。

我們關心的是內存占用情況,請單擊 Memory 選項卡,圖 10 顯示了 Java 程序所用內存的一小部分。


圖 10. TopToBottom Memory 選項卡
TopToBottom 內存

顯 示的內容和 PrcView 類似,但是它僅僅顯示了虛擬空間中的提交內存,而沒有保留內存。但是它有兩個優點。首先,它可以更詳盡地描述頁面。比如在圖 10 中專門標記了 Thread 3760 棧區域,而不僅僅是一些讀/寫數據。它是別的其他數據區包括環境、進程參數、進程堆、線程棧和線程環境塊(TEB)。其次,您可以直接在 TopToBottom 中瀏覽甚至搜索內存。您可以搜索文本字符串或者最多 16 字節的十六進制序列。可以將十六進制搜索限制在特定的序列中,在檢索地址引用時這一點很方便。

TopToBottom 也有快照功能,可以把進程的所有信息轉儲到剪貼板中。

VADump

VADump 是一種方便的命令行工具,屬于 Microsoft ? Platform SDK 包(請參閱 參考資料 )的一部分。它的目的是轉儲特定進程的虛擬地址空間和駐留集。使用 VADump 最簡單的方法就是在命令行中輸入以下命令:

            vadump  
            
process_id

process_id 是要分析的進程號。如果不帶參數,則可以顯示 VADump 完整的用法說明。我們建議您將結果通過管道保存到文件中(如 vadump 1234 > output.txt ),因為 VADump 生成的信息非常多,一屏放不下。

輸出中首先給出進程虛擬地址空間的索引:

            >vadump -p 3904
            
Address: 00000000 Size: 00010000
State Free
Address: 00010000 Size: 00002000
State Committed
Protect Read/Write
Type Private
Address: 00012000 Size: 0000E000
State Free
Address: 00020000 Size: 00001000
State Committed
Protect Read/Write
Type Private
Address: 00021000 Size: 0000F000
State Free
Address: 00030000 Size: 00010000
State Committed
Protect Read/Write
Type Private
Address: 00040000 Size: 0003B000 RegionSize: 40000
State Reserved
Type Private
................................

(為便于閱讀,省略了部分行。)

對于每個塊,都可以看到下列信息:

  • Address :十六進制格式,相對于進程虛擬地址空間起始位置的偏移量。
  • Size :字節數,用十六進制表示。
  • State :自由、保留或提交。
  • Protection status :只讀或/讀寫。
  • Type :私有(不能被其他進程訪問)、映射(直接來自文件系統)或鏡像(可執行代碼)。

然后列出進程使用的所有 DLL 及其大小,后面是工作集和分頁文件使用的統計信息。

目前為止,所提到的信息都可以從其他工具獲得。但是通過 VADump 的 -o 選項還可以得到更有啟發作用的輸出結果。它可以生成當前工作集的快照(某一給定時刻實際存在于主存中的頁面)。關于該選項文檔沒有提供多少信息,但是在確 定駐留集中最重要的部分時,這是一個極其有用的工具,這樣能夠確定最可能的內存優化目標。通過定期記錄內存快照,您還可以使用它確定是否存在內存泄漏。這 種模式下,輸出從虛擬地址空間中提交頁面的詳盡轉儲開始,無論這些頁面是否還在主存中:

            >vadump -o -p 3904
            
0x00010000 (0) PRIVATE Base 0x00010000
0x00011000 (0) PRIVATE Base 0x00010000
0x00020000 (0) PRIVATE Base 0x00020000
0x00030000 (0) PRIVATE Base 0x00030000
0x00031000 (0) Private Heap 2
0x00032000 (0) Private Heap 2
0x00033000 (0) Private Heap 2
0x00034000 (0) Private Heap 2
0x00035000 (0) Private Heap 2
0x00036000 (0) Private Heap 2
0x00037000 (0) Private Heap 2
0x00038000 (0) Private Heap 2
0x00039000 (0) Private Heap 2
0x0003A000 (0) Private Heap 2
0x0003B000 (0) Private Heap 2
0x0003C000 (0) Private Heap 2
0x0003D000 (0) Private Heap 2
0x0003E000 (0) Private Heap 2
0x0003F000 (0) Private Heap 2
0x0007C000 (0) Stack for ThreadID 00000F64
0x0007D000 (0) Stack for ThreadID 00000F64
0x0007E000 (0) Stack for ThreadID 00000F64
0x0007F000 (0) Stack for ThreadID 00000F64
0x00080000 (7) UNKNOWN_MAPPED Base 0x00080000
0x00090000 (0) PRIVATE Base 0x00090000
0x00091000 (0) Process Heap
0x00092000 (0) Process Heap
0x00093000 (0) Process Heap
...........................

滾動到這個長長的列表的最后,您會看到更有趣的信息:目前駐留主存的進程頁面的頁表映射清單:

            0xC0000000 > (0x00000000 : 0x003FFFFF)   132 Resident Pages
            
(0x00280000 : 0x00286000) > jsig.dll
(0x00290000 : 0x00297000) > xhpi.dll
(0x002A0000 : 0x002AF000) > hpi.dll
(0x003C0000 : 0x003D8000) > java.dll
(0x003E0000 : 0x003F7000) > core.dll
(0x00090000 : 0x00190000) > Process Heap segment 0
(0x00190000 : 0x001A0000) > Private Heap 0 segment 0
(0x001A0000 : 0x001B0000) > UNKNOWN Heap 1 segment 0
(0x00380000 : 0x00390000) > Process Heap segment 0
(0x00030000 : 0x00040000) > Private Heap 2 segment 0
(0x00390000 : 0x003A0000) > Private Heap 3 segment 0
(0x00040000 : 0x00080000) > Stack for thread 0
0xC0001000 > (0x00400000 : 0x007FFFFF) 13 Resident Pages
(0x00400000 : 0x00409000) > java.exe
.................................................................

每個映射都對應頁表中的一項,組成了進程工作集另一個 4KB。但要從這些映射中發現應用程序的哪些部分使用了最多的內存仍然很困難,但幸運的是下一部分輸出給出了有用的總結:

            Category                   Total       Private  Shareable  Shared
            
Pages KBytes KBytes KBytes KBytes
Page Table Pages 20 80 80 0 0
Other System 10 40 40 0 0
Code/StaticData 1539 6156 3988 1200 968
Heap 732 2928 2928 0 0
Stack 9 36 36 0 0
Teb 5 20 20 0 0
Mapped Data 30 120 0 0 120
Other Data 1314 5256 5252 4 0
Total Modules 1539 6156 3988 1200 968
Total Dynamic Data 2090 8360 8236 4 120
Total System 30 120 120 0 0
Grand Total Working Set 3659 14636 12344 1204 1088

最有趣的兩個值通常是 Heap (即 Windows 進程堆)和 Other Data。直接通過調用 Windows API 分配的內存組成了進程堆部分,Other Data 中包括 Java 堆。Grand Total Working Set 對應 Task Manager 的 Mem Usage 和 TEB 字段(進程的線程環境塊所需要的內存,TEB 是一種 Windows 內部結構)。

最后,在 VADump -o 輸出的最下端總結了 DLL、堆和線程棧對工作集的相對貢獻:

            Module Working Set Contributions in pages
            
Total Private Shareable Shared Module
9 2 7 0 java.exe
85 5 0 80 ntdll.dll
43 2 0 41 kernel32.dll
15 2 0 13 ADVAPI32.dll
11 2 0 9 RPCRT4.dll
53 6 0 47 MSVCRT.dll
253 31 222 0 jvm.dll
6 3 3 0 jsig.dll
7 4 3 0 xhpi.dll
15 12 3 0 hpi.dll
12 2 0 10 WINMM.dll
21 2 0 19 USER32.dll
14 2 0 12 GDI32.dll
6 2 0 4 LPK.DLL
10 3 0 7 USP10.dll
24 18 6 0 java.dll
22 16 6 0 core.dll
18 14 4 0 zip.dll
915 869 46 0 jitc.dll
Heap Working Set Contributions
6 pages from Process Heap (class 0x00000000)
0x00090000 - 0x00190000 6 pages
2 pages from Private Heap 0 (class 0x00001000)
0x00190000 - 0x001A0000 2 pages
0 pages from UNKNOWN Heap 1 (class 0x00008000)
0x001A0000 - 0x001B0000 0 pages
1 pages from Process Heap (class 0x00000000)
0x00380000 - 0x00390000 1 pages
715 pages from Private Heap 2 (class 0x00001000)
0x00030000 - 0x00040000 15 pages
0x008A0000 - 0x009A0000 241 pages
0x04A60000 - 0x04C60000 450 pages
0x054E0000 - 0x058E0000 9 pages
1 pages from Private Heap 3 (class 0x00001000)
0x00390000 - 0x003A0000 1 pages
7 pages from Private Heap 4 (class 0x00001000)
0x051A0000 - 0x051B0000 7 pages
Stack Working Set Contributions
4 pages from stack for thread 00000F64
1 pages from stack for thread 00000F68
1 pages from stack for thread 00000F78
1 pages from stack for thread 00000F7C
2 pages from stack for thread 00000EB0

通過這種模式還可以用 VADump 獲得兩個或更多 Java 進程的總和內存占用情況(請參閱本文后面的 技巧和竅門 )。

Sysinternals Process Explorer

更有用的內存分析工具來自 Sysinternals 公司(請參閱 參考資料 )。其中一個工具是圖形化的進程管理器,如圖 11 所示,它可以作為 Task Manager 的高級代替品。


圖 11. Process Explorer 進程樹
Process Explorer

Process Explorer 具有和 Task Manager 相同的功能。比方說,您可以得到整個系統性能的動態圖形(通過 View --> System Information... ),也可用類似的方式配置主進程視圖中的列。在 Process --> Properties... 中,Process Explorer 提供了進程的更多信息,比如完整路徑和命令行、線程、CPU 實用的動態圖表和私有內存。它的用戶界面非常好,如圖 11 所示。它還可以觀察 DLL 的信息和進程的句柄。您可以使用 Options --> Replace Task Manager 用 Process Explorer 代替默認的 Task Manager。

Sysinternals ListDLLs

還可以從 Sysinternals 下載兩個命令行工具:ListDLLs 和 Handle。如果希望在腳本或者程序中集成某種形式的內存監控,這兩個工具非常有用。

ListDLLs 用于觀察 DLL,DLL 可能造成很多內存占用。使用之前請將其添加到路徑中,并使用幫助選項獲得用法說明。您可以用進程 ID 或進程名調用它。下面是我們的 Java 程序調用 DLL 的列表:

            >listdlls -r 3904
            
ListDLLs V2.23 - DLL lister for Win9x/NT
Copyright (C) 1997-2000 Mark Russinovich
http://www.sysinternals.com
---------------------------------------------------------------------
java.exe pid: 3904
Command line: java -mx1000m -verbosegc Hello
Base Size Version Path
0x00400000 0x9000 141.2003.0005.0022 C:/WINDOWS/system32/java.exe
0x77f50000 0xa7000 5.01.2600.1217 C:/WINDOWS/System32/ntdll.dll
0x77e60000 0xe6000 5.01.2600.1106 C:/WINDOWS/system32/kernel32.dll
0x77dd0000 0x8d000 5.01.2600.1106 C:/WINDOWS/system32/ADVAPI32.dll
0x78000000 0x87000 5.01.2600.1361 C:/WINDOWS/system32/RPCRT4.dll
0x77c10000 0x53000 7.00.2600.1106 C:/WINDOWS/system32/MSVCRT.dll
0x10000000 0x178000 141.2004.0003.0001 C:/Java141/jre/bin/jvm.dll
### Relocated from base of 0x10000000:
0x00280000 0x6000 141.2004.0003.0001 C:/Java141/jre/bin/jsig.dll
### Relocated from base of 0x10000000:
0x00290000 0x7000 141.2004.0003.0001 C:/Java141/jre/bin/xhpi.dll
### Relocated from base of 0x10000000:
0x002a0000 0xf000 141.2004.0003.0001 C:/Java141/jre/bin/hpi.dll
0x76b40000 0x2c000 5.01.2600.1106 C:/WINDOWS/system32/WINMM.dll
0x77d40000 0x8c000 5.01.2600.1255 C:/WINDOWS/system32/USER32.dll
0x7e090000 0x41000 5.01.2600.1346 C:/WINDOWS/system32/GDI32.dll
0x629c0000 0x8000 5.01.2600.1126 C:/WINDOWS/system32/LPK.DLL
0x72fa0000 0x5a000 1.409.2600.1106 C:/WINDOWS/system32/USP10.dll
### Relocated from base of 0x10000000:
0x003c0000 0x18000 141.2004.0003.0001 C:/Java141/jre/bin/java.dll
### Relocated from base of 0x10000000:
0x003e0000 0x17000 141.2004.0003.0001 C:/Java141/jre/bin/core.dll
### Relocated from base of 0x10000000:
0x04a40000 0x12000 141.2004.0003.0001 C:/Java141/jre/bin/zip.dll
### Relocated from base of 0x10000000:
0x04df0000 0x3a1000 141.2004.0003.0001 C:/Java141/jre/bin/jitc.dll

也可以使用 listdlls -r java 命令,列出所有運行的 Java 進程及其使用的 DLL。

Sysinternals Handle

Handle 給出進程所用句柄(文件、套接字等)的列表。解壓 Handle 下載文件,并將其添加到路徑中,然后試著運行它。對于我們的 Java 程序,輸出結果如下所示:

            >handle -p 3904
            
Handle v2.2
Copyright (C) 1997-2004 Mark Russinovich
Sysinternals - www.sysinternals.com
------------------------------------------------------------------
java.exe pid: 3904 99VXW67/cem
c: File C:/wsappdev51/workspace/Scratch
4c: File C:/wsappdev51/workspace/Scratch/verbosegc.out
50: File C:/wsappdev51/workspace/Scratch/verbosegc.out
728: File C:/WebSphere MQ/Java/lib/com.ibm.mq.jar
72c: File C:/WebSphere MQ/Java/lib/fscontext.jar
730: File C:/WebSphere MQ/Java/lib/connector.jar
734: File C:/WebSphere MQ/Java/lib/jms.jar
738: File C:/WebSphere MQ/Java/lib/jndi.jar
73c: File C:/WebSphere MQ/Java/lib/jta.jar
740: File C:/WebSphere MQ/Java/lib/ldap.jar
744: File C:/WebSphere MQ/Java/lib/com.ibm.mqjms.jar
748: File C:/WebSphere MQ/Java/lib/providerutil.jar
74c: File C:/Java141/jre/lib/ext/oldcertpath.jar
750: File C:/Java141/jre/lib/ext/ldapsec.jar
754: File C:/Java141/jre/lib/ext/JawBridge.jar
758: File C:/Java141/jre/lib/ext/jaccess.jar
75c: File C:/Java141/jre/lib/ext/indicim.jar
760: File C:/Java141/jre/lib/ext/ibmjceprovider.jar
764: File C:/Java141/jre/lib/ext/ibmjcefips.jar
768: File C:/Java141/jre/lib/ext/gskikm.jar
794: File C:/Java141/jre/lib/charsets.jar
798: File C:/Java141/jre/lib/xml.jar
79c: File C:/Java141/jre/lib/server.jar
7a0: File C:/Java141/jre/lib/ibmjssefips.jar
7a4: File C:/Java141/jre/lib/security.jar
7a8: File C:/Java141/jre/lib/graphics.jar
7ac: File C:/Java141/jre/lib/core.jar

可以看出我們的進程中有一個句柄,該句柄指向類路徑目錄和幾個 JAR 文件。事實上,該進程還有更多的句柄,但默認情況下該工具僅顯示引用文件的句柄。使用 -a 參數就可以顯示其他句柄:

            >handle -a -p 3904
            
Handle v2.2
Copyright (C) 1997-2004 Mark Russinovich
Sysinternals - www.sysinternals.com
------------------------------------------------------------------
java.exe pid: 3904 99VXW67/cem
c: File C:/wsappdev51/workspace/Scratch
4c: File C:/wsappdev51/workspace/Scratch/verbosegc.out
50: File C:/wsappdev51/workspace/Scratch/verbosegc.out
71c: Semaphore
720: Thread java.exe(3904): 3760
724: Event
728: File C:/WebSphere MQ/Java/lib/com.ibm.mq.jar
72c: File C:/WebSphere MQ/Java/lib/fscontext.jar
730: File C:/WebSphere MQ/Java/lib/connector.jar
734: File C:/WebSphere MQ/Java/lib/jms.jar
738: File C:/WebSphere MQ/Java/lib/jndi.jar
73c: File C:/WebSphere MQ/Java/lib/jta.jar
740: File C:/WebSphere MQ/Java/lib/ldap.jar
744: File C:/WebSphere MQ/Java/lib/com.ibm.mqjms.jar
748: File C:/WebSphere MQ/Java/lib/providerutil.jar
74c: File C:/Java141/jre/lib/ext/oldcertpath.jar
750: File C:/Java141/jre/lib/ext/ldapsec.jar
754: File C:/Java141/jre/lib/ext/JawBridge.jar
758: File C:/Java141/jre/lib/ext/jaccess.jar
75c: File C:/Java141/jre/lib/ext/indicim.jar
760: File C:/Java141/jre/lib/ext/ibmjceprovider.jar
764: File C:/Java141/jre/lib/ext/ibmjcefips.jar
768: File C:/Java141/jre/lib/ext/gskikm.jar
76c: Key HKCU
770: Semaphore
774: Thread java.exe(3904): 3964
778: Event
77c: Semaphore
780: Semaphore
784: Thread java.exe(3904): 3960
788: Event
78c: Thread java.exe(3904): 3944
790: Event
794: File C:/Java141/jre/lib/charsets.jar
798: File C:/Java141/jre/lib/xml.jar
79c: File C:/Java141/jre/lib/server.jar
7a0: File C:/Java141/jre/lib/ibmjssefips.jar
7a4: File C:/Java141/jre/lib/security.jar
7a8: File C:/Java141/jre/lib/graphics.jar
7ac: File C:/Java141/jre/lib/core.jar
7b0: Event
7b4: Thread java.exe(3904): 3940
7b8: Event
7bc: Semaphore
7c0: Directory /BaseNamedObjects
7c4: Key HKLM/SOFTWARE/Windows NT/Drivers32
7c8: Semaphore
7cc: Semaphore
7d0: Event
7d4: Desktop /Default
7d8: WindowStation /Windows/WindowStations/WinSta0
7dc: Event
7e0: WindowStation /Windows/WindowStations/WinSta0
7e4: Event
7e8: Section
7ec: Port
7f0: Directory /Windows
7f4: Key HKLM
7f8: Directory /KnownDll
7fc: KeyedEvent /KernelObjects/CritSecOutOfMemoryEvent

如果關心內存的使用,句柄是一個重要因素,因為每個句 柄都要消耗一些空間。具體的數量取決于操作系統版本和句柄的類型。一般而言,句柄不應該對內存占用產生很大影響。只要數一數該工具輸出的行數,就可以判定 句柄是不是太多,或者是否還在增長。無論出現哪種情況,都值得注意,建議進行更細致的分析。







技巧和竅門

現在您已經操作(不是雙關語,handle 還有一個含義是句柄)了我們要介紹的所有工具,下面是您單獨或一起使用這些工具,改進內存監控的一些方法。

尋找進程 ID

為了找到應用程序的進程 ID,以便在 VADump 這樣的命令行工具中使用,請在 Task Manager 中打開 Applications 選項卡右擊所關心的進程。選擇 Go To Process ,這樣就會在 Processes 選項卡中看到對應的 ID。

確定一個 Java 進程

是 否對那些都命名為 Java 或 javaw 的進程感到困惑,希望找出您要分析的那個進程?如果從 IDE 或腳本中啟動 Java 進程,要確定使用了哪一個 JVM 和發送給 Java 進程的命令行參數可能很困難。這些信息可以在 TopToBottom Startup 選項卡中找到。您可以看到調用 JVM 使用的完整命令行和進程啟動的時間。

確定大量占用句柄的進程

是 否遇到過保存文件卻得到提示說文件正被另一個進程使用的情況?或者嘗試關閉您認為可靠的程序而得到錯誤消息的情況?您可以使用 SysInternals Process Explorer 工具的 Handle Search 功能發現誰在搗亂。只要打開 Search 對話框并輸入文件名即可。ProcExp 將遍歷所有打開的句柄,并確定相應的進程。最終常常會發現,關閉用戶界面后,編輯器或者 Web 瀏覽器還留下一個小的存根進程在運行。

調查有多少內存被共享

您可以使用 VADump 的 -o 選項獲得進程當前工作集的詳細視圖,以及有多少是共享的。獲得一個 Java 程序在系統上運行的內存轉儲,然后再啟動另一個并轉儲。只要比較每個結果的 Code/StaticData 部分,就會發現“Shareable”字節變成了“Shared”,從而稍微降低了內存占用的增加。

清理駐留集

Windows 實現了一種“清除”進程駐留集的策略,在其看起來不再有用的時候予以清除。為了說明這一點,打開 Task Manager 的 Processes 選項框,便可以看到要監控的應用程序進程,然后最小化應用程序窗口,看看 Mem Usage 字段發生了什么變化!

確定應用程序需要的最少內存

對于 Windows Server 2003 和 Windows NT,Microsoft 提供了一個有趣的稱為 ClearMem 的工具,如果希望進一步研究 Windows 下應用程序使用內存的情況,它可能非常有用(請參閱 參考資料 )。該工具確定了實際內存的大小,分配足夠的內存,很快地占用分配的內存然后將其釋放。這樣就增加了其他應用程序的內存占用壓力,反復運行 ClearMem 的結果是迫使應用程序占用的內存數量減少到最小。







結束語

本 文簡要介紹了 Windows 如何管理內存,考察了一些最有用的免費工具,您可以用這些工具監控 Java 應用程序的內存使用。無疑您還會發現和使用其他的工具,無論從 Web 上免費下載產品還是購買商業產品,我們都希望澄清相互矛盾的術語會對您有所幫助。通常要確定您測量的目標的惟一方法就是做試驗,比如我們用于示范 Task Manager 的 VM Size(虛擬內存大小)和 Mem Usage(內存使用)含義的 C 程序。

當然這些工具只能幫助確定問題的所在,如何解決還要靠您自己。多數時候您會發現 Java 堆獲取了內存的一大部分,您需要深入分析代碼,確定對象引用是否超出了必要的時間。這方面有更多的工具和文章可以提供幫助, 參考資料 部分給出了一些有用的鏈接,可以為您指出正確的方向。








下載

描述 名字 大小 下載方法 A C program to demonstrate how Windows uses memory
experiment.c 3KB HTTP
關于下載方法的信息


參考資料



作者簡介

Emma Shepherd 的照片

Emma Shepherd 于 2002 年 Warwick 大學獲得計算機科學學士學位,畢業后就加入了 IBM。她的上一個項目是關于 Java Web 服務的,她還參與了 IBM WebSphere SDK for Web Services 和 Eclipse 插件的開發。業余時間她喜歡彈鋼琴,學說塞爾維亞語。


Martin Trotter 的照片

Martin Trotter 畢業于 Southampton 大學,獲得了電氣方面的學位,幾年前剛加入 IBM。從一開始他就參與了 Java 的研究,在 JVM 和 JIT 方面擁有廣泛的經驗,并曾領導過垃圾收集團隊。其業余愛好包括制作陶器、散步、騎自行車兜風和做木工等。


Caroline Maynard 的照片

Caroline Maynard 從 Sussex 大學獲得了數學學位,畢業后一直在 IBM 工作。她最近領導了 IBM Java ORB 的開發,對 Java 程序的內存占用很感興趣。工作之余,她喜歡參加溫徹斯特交響樂隊的演出,從她的小貓爪子底下挽救小生物,陪著孩子到處旅游,有時間的時候,會列一列要做的 所有工作。


Matthew Peters 的照片

Matthew Peters 多年前從劍橋的女王學院獲得了數學學位,此后一直在 IBM 工作。最近幾年從事 IBM JVM 垃圾收集程序和 JVM 性能提升的研究。業余時間喜歡下圍棋,彈奏古典吉他,或者和家人騎車旅行

監控Java應用程序Windows內存使用情況


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 欧美日本高清视频在线观看 | 中国一级特黄高清免费的大片 | 狠狠色丁香六月色 | 欧美久久超级碰碰碰二区三区 | 成年人的毛片 | 欧美一区二区三区精品 | 成人精品一级毛片 | 第一国内永久免费福利视频 | 国产日韩欧美亚洲综合首页 | 日本欧美在线观看 | 女人大毛片一级毛片一 | 久久国产美女免费观看精品 | 久青草中文字幕精品视频 | 四虎影院永久在线观看 | 国产在线观看自拍 | 手机看片欧美日韩 | 亚洲999| 国产高清狼人香蕉在线观看 | 亚洲高清在线mv | 99精品欧美一区二区三区 | 婷婷综合在线 | 日本护士a做爰免费观看 | 免费看欧美一级特黄a大片 免费看欧美一级特黄a大片一 | 久久97精品久久久久久清纯 | 久 在线播放 | 狠狠色噜噜狠狠狠狠 | 外国成人网在线观看免费视频 | 欧美日日射 | 久热综合 | 欧美激情在线精品三区 | 色五月在线视频 | 四虎在线视频 | 中文字幕人成不卡一区 | 图片专区亚洲 欧美 另类 | 成人在线第一页 | 操白嫩美女 | 色在线播放 | 一级一毛片a级毛片欧美 | 精品国产一区二区三区免费 | 久在线精品视频 | 日本高清无吗免费播放 |