如何監控 Tomcat 的內存占用情況
目錄
- 1 JVM 內存模型中的區域
- 1.1 線程棧區
- 1.2 Java Heap 區
- 1.3 靜態方法區
- 1.4 JDK 8.0中的元空間
- 2 JDK 工具的使用
- 3 查看 GC 日誌信息
- 4 添加 JMS 遠程監控
Tomcat 是運行在 JVM(Java Virtual Machine) 中的一個 Java 進程, 它在運行過程中對內存的占用情況, 可以借助一些 JDK 的工具進行監控, 為優化提供數據支撐.
1 JVM 內存模型中的區域
1.1 線程棧區
壓入線程棧的每個棧幀(Stack Frame)中, 包含了程序指令以及局部變量表, 每個方法調用對應一個棧幀.
程序指令包括程序計數器(PCR), 記錄程序執行到的位置, 便於方法調用或多線程切換結束後的工作恢復.
局部變量表包括各種基本數據類型: boolean、byte、char、short、int、float、long、double以及對象的引用.
註意: 每個線程都有獨立的棧, 稱之為線程棧, 它們是互相隔離的.
1.2 Java Heap 區
Java Heap是被所有線程共享的一塊內存區域, 在虛擬機啟動時創建. 此內存區域的唯一目的就是存放對象實例, 幾乎所有的對象實例都在這裏分配內存.
1.3 靜態方法區
又稱為永久代(Perm Generation), 用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據.
對於永久代的常見配置有: -XX:PermSize=256m -XX:MaxPermSize=512m
說明: JDK 8.0中用Meta Space(元空間)替代Perm Generation, 因此在配置 JVM 啟動參數的時候, 需要作如下配置:
-XX:MetaspaceSize=256m # 對比JDK 7.0的 PermSize
-XX:MaxMetaspaceSize=512m # 對比JDK 7.0的 MaxPermSize
1.4 JDK 8.0中的元空間
JDK 8.0 的HotSpot 實現中, 使用本地內存來存儲類的元數據, 這個區域被稱為元空間.
元空間有如下特點:
- 充分利用了Java語言規範中的好處: 類及相關元數據的生命周期與類加載器的生命周期一致;
- 每個類加載器都有各自專用的存儲空間;
- 元空間只進行線性分配;
- 不會單獨回收某個類;
- 省掉了GC掃描及壓縮的時間;
- 元空間中對象的位置是固定的;
- 如果GC發現某個類加載器不再存活, 它就會把與這個類加載器相關的空間全部回收.
元空間的內存分配模型:
- 絕大多數類的元數據空間都從本地內存中分配;
- 用來描述類的元數據的類也被刪除了;
- 分元數據分配了多個虛擬內存空間;
- 給每個類加載器分配一個內存塊的列表, 塊的大小取決於類加載器的類型; sun/反射/代理對應的類加載器的塊會小一些;
- 歸還內存塊, 釋放內存塊列表;
- 一旦元空間的數據被清空了, 虛擬內存的空間就會被回收;
- 減少碎片的策略.
2 JDK 工具的使用
JDK自帶的工具位於
${JAVA_HOME}/bin/
目錄下.
JConsole 可以簡單明了地查看到內存的使用情況, 線程的狀態, 當前加載的類的總量等.
JVisualVM 可以下載插件(如GC等), 進而查看更豐富的信息. 如果是分析本地的Tomcat的話, 還可以進行內存抽樣等, 檢查每個類的使用情況.
jps 查看本地運行著的 Java 進程, 及其進程號、進程啟動的路徑等信息;
jmap 查看垃圾收集策略即 JVM 內存占用情況:
jmap -heap pid
# 查看垃圾收集策略, 以及堆內存的分配、使用情況.jmap -clstats pid
# 查看類加載器的統計數據 --- 此命令調用了sun.jvm.hotspot.runtime.VM.initialize()
方法, 會導致該 pid 對應的 JVM 進程阻塞.jmap -histo [pid]
# 按照內存使用大小倒序列出內存中的實例類型.jstack 查看線程棧:
jstack pid
# 列出該 pid 對應 JVM 的所有線程棧描述, 主要包括每個線程的狀態以及堆棧內各棧幀的方法全限定名、代碼位置. 註意: 這些信息的顯示只是為了便於開發人員閱讀, 並不是棧中存的就是這些信息.jstat 實時查看堆內存的使用情況:
# 使用方法: jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]] # 查看可使用的選項: jstat –options -class # 類加載情況的統計 -compiler # HotSpot中即時編譯器編譯情況的統計 -gc -gccapacity # 新生代、老年代以及永久代的存儲容量情況 -gccause -gcmetacapacity # 元數據區的容量 -gcnew # 新生代垃圾回收信息 -gcnewcapacity # 新生代的存儲容量 -gcold # 老年代垃圾回收信息 -gcoldcapacity # 老年代的存儲容量 -gcutil # 實時查看GC信息 -printcompilation # HotSpot編譯方法的統計
使用示例: 間隔5s, 每隔10條輸出一次頭信息, 打印進程號為3308的JVM進程的堆內存使用情況, 以及各代垃圾回收的次數及時間:
jstat -gcutil -h10 77545 5000顯示信息如下:
- 參數說明:
S0: Heap上的Survivor Space 0區已使用空間的百分比 S1: Heap上的Survivor Space 1區已使用空間的百分比 E: Heap上的Eden Space區已使用空間的百分比 O: Heap上的Old Space區已使用空間的百分比 M: Meta Space(元數據區)已使用空間的百分比 YGC: 從應用程序啟動到采樣時發生Young GC的次數 YGCT: 從應用程序啟動到采樣時Young GC所用的時間(單位: 秒) FGC: 從應用程序啟動到采樣時發生Full GC的次數 FGCT: 從應用程序啟動到采樣時Full GC所用的時間(單位: 秒) GCT: 從應用程序啟動到采樣時用於垃圾回收的總時間(單位: 秒)
3 查看 GC 日誌信息
可以通過配置JVM的啟動參數, 打印類的加載情況及對象的回收信息, 可以打印到屏幕或指定文件中, 默認也會打印到catalina.log中. Tomcat容器的JVM啟動參數配置文件是: ${TOMCAT_HOME}/bin/catalina.sh
, 具體參數如下:
-verbose:gc # 在輸出設備顯示垃圾收集信息(JVM發生內存回收時輸出相關信息)
-XX:+PrintGC # 輸出GC日誌, 形式: Full GC 118250K->113543K(130112K), 0.0094143 secs
-XX:+PrintGCDetails # 輸出GC詳細日誌, 形式: GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs[Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs]
-XX:+PrintGCTimeStamps # 輸出GC的時間戳, 以基準時間的形式輸出: 11.851: [GC 98328K->93620K(130112K), 0.0082960 secs], 11.851是JVM啟動後的秒數.
-XX:+PrintGCDateStamps # 輸出GC的時間戳, 以日期的形式輸出: 2018-08-28T21:53:59.234+0800.
-XX:+PrintGCApplicationStoppedTime # 打印垃圾回收期間程序暫停的時間, 即GC消耗的時間. 可與上面混合使用. 輸出形式: Total time for which application threads were stopped: 0.0468229 seconds
-XX:+PrintGCApplicationConcurrentTime # 打印每次垃圾回收前, 程序未中斷的執行時間, 即相鄰2次GC的間隔. 可與上面混合使用. 輸出形式: Application time: 0.5291524 seconds
-XX:+PrintTenuringDistribution # 觀察各個Age的對象總大小
-XX:PrintHeapAtGC # 打印GC前後的詳細堆棧信息.
-XX:+HeapDumpOnOutOfMemoryError # 發生OOM時自動dump堆棧信息, 以便後續分析.
-Xloggc:../logs/gc.log # 與上面選項配合使用, 將日誌信息輸出到指定的文件以便後續分析.
4 添加 JMS 遠程監控
對部署在局域網內其他服務器上的Tomcat, 可以打開JMX監控端口, 就可以在另外的服務器上通過該端口查看常用的參數(一些比較復雜的功能不支持).
配置方法: 同樣是在JVM啟動參數中配置, 配置如下:
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Djava.rmi.server.hostname=172.16.11.62 # 設置JVM的JMS監聽的IP地址, 防止錯誤監聽為本機127.0.0.1地址
-Dcom.sun.management.jmxremote.port=1090 # 設置JVM的JMS監控的端口
-Dcom.sun.management.jmxremote.ssl=false # 設置JVM的JMS監控不實用SSL
-Dcom.sun.management.jmxremote.authenticate=false # 設置JVM的JMS監控不需要認證
參考資料:
JVM 運行時內存使用情況監控
版權聲明
作者: ma_shoufeng(馬瘦風)
出處: 博客園 馬瘦風的博客
您的支持是對博主的極大鼓勵, 感謝您的閱讀.
本文版權歸博主所有, 歡迎轉載, 但未經博主同意必須保留此段聲明, 且在文章頁面明顯位置給出原文鏈接, 否則博主保留追究法律責任的權利.
如何監控 Tomcat 的內存占用情況