JVM優化實戰

1 GC相關內存

1.1 內存劃分

1.1.1 堆(Heap)

存放 new MyClass() 的對象,是GC的主要區域,
-Xms / -Xmx 分別是堆的初始容量、最大可擴展容量,建議初始值設置爲最大值,以免反覆擴展或縮減的開銷;

  • 新生代(Young Generation):又劃分爲 Eden(伊甸園,新生區), Survivor#0(倖存區S0), Survivor#1(倖存區S1)

  • 老年代(Tenured Generation)

-XX:NewRatio 是“老年代 / 新生代”的比例,默認值爲 2;
-XX:SurvivorRatio 是指 Eden/Survivor#0 的比例,而Survivor#0 與 Survivor#1 容量相同;

1.1.2 永久代(Permanent Generation)

存放類信息、常量、大對象(比如 new byte[n]對象);
-XX:PermSize / -XX:MaxPermSize 爲永久代的初始、最大容量,建議初始容量指定爲最大容量;
JDK8 中,永久代被完全的移除了,包括相關參數 -XX:PermSize / -XX:MaxPermSize。改用 Metaspace,通過參數-XX:MetaspaceSize / -XX:MaxMetaspaceSize / -XX:CompressedClassSpaceSize 設定;

1.1.3 實例解析

選項 -Xms300M -Xmx300M -XX:NewRatio=2 -XX:SurvivorRatio=8 -XX:PermSize=100M -XX:MaxPermSize=100M 含義爲:

  • 永久代固定尺寸爲 100M;

  • 整個堆固定尺寸爲 300M,其中“老年代 / 新生代”爲-XX:NewRatio=2,所以老年代爲 200M,新生代爲 100M;

  • 新生代總共 100M,其中“Eden / Survivor0”爲-XX:SurvivorRatio=8,所以 Eden 爲 80M,Survivor0=Survivor1=10M。
    官方資料:http://www.oracle.com/technetwork/articles/java/vmoptions-jsp-140102.html

1.2 JVM內存分配策略

1.2.1. 對象優先分配在 Eden

首先嚐試在 Eden 分配,若 Eden 空間不足,就發起 YoungGC(簡稱YGC);

  • 如果倖存對象(被根對象直接或間接引用)在 SurvivorTo 能放下,則存活對象全部移入 SurvivorTo;

  • 如果倖存對象在 SurvivorTo 存放不下,則存活對象全部移入老年代;
    如果此時老年代空間不足,則發起一次 FullGC(簡稱FYC,整個系統停頓,老年代也參與回收);
    如果 FullGC 時空間仍然週轉不過來,則報 OutOfMemoryError 並導致進程結束;

  • 如果YGC/FGC能週轉過來,則新對象分配在 Eden 中;

1.2.2. 大對象直接分配在老年代

所謂的大對象是指,需要大量連續內存的 Java 對象,尤其是長字符串或數組,比如 byte[n] 對象;
可以指定多大才算大對象(只對 Serial/ParNew 有效);

1.2.3. 長期存活對象移入老年代

經歷 n 次 YGC 仍然存活的對象,下次 YGC 時將被移入老年代;
可以設置該數值:-XX:MaxTenuringThreshold=15(默認)

1.2.4. 永久代滿了也會導致 FullGC

老年代、永久代的垃圾收集是捆綁在一起的,因此無論兩者誰滿了,都會觸發兩者的FullGC。

1.2.5. 動態對象年齡判定

如果 Survivor 相同年齡對象佔用空間達到一半,則大於等於該年齡的對象都移入老年代;

1.2.6. 冒險模式

JDK 6u24 之後,總是開啓冒險模式(先嚐試 YGC,以免 FGC 頻繁);
每次 YGC 之前,如果老年代最大連續空間,大於新生代所有對象空間之和,則 YGC 肯定成功,否則:

  • 如果老年代最大連續空間,大於歷次晉升老年代的平均值,則先冒險嘗試 YGC;

  • 如果老年代最大連續空間,小於歷次晉升老年代的平均值,則直接 FullGC;

2 JVM優化原則

2.1 優化目標

2.1.1 儘量減少 YoungGC,以減少代碼停頓

2.1.2 儘量減少 FullGC,以減少系統停頓

一天最多 FullGC 一次,最好在系統空閒期(如深夜);

2.2 優化方法

2.2.1 代碼角度

縮短對象生命期,尤其是大對象

2.2.2 JVM參數角度

優化JVM參數以減少YGC/FGC次數,可替換收集器

3 服務端開啓 JMX/jstatd

這兩項功能必須開啓,下面的可視化工具 VisualVM 要用到。

3.1 設置系統環境變量

### 下文多處用到此變量,統一維護在系統環境變量裏
set JMX_HOSTNAME=192.168.214.128 ## Windows
export JMX_HOSTNAME=192.168.214.128 ## Linux

3.2 開啓 JMX(指定端口 1090)

需要注意的是,如果服務端 JMX 開啓了修改和控制權限,此時如果不驗證監控客戶端的身份,那麼所有用戶都可以修改和控制 Tomcat 服務,所以重要的服務器應該開啓用戶名和密碼驗證。

3.2.1 準備用戶驗證文件

### Windows
copy/b "%JAVA_HOME%\jre\lib\management\jmxremote.password.template" "%CATALINA_BASE%\conf\jmxremote.password"
copy/b "%JAVA_HOME%\jre\lib\management\jmxremote.access" "%CATALINA_BASE%\conf\jmxremote.access"

### Linux
cp "$JAVA_HOME/jre/lib/management/jmxremote.password.template" "$CATALINA_BASE/conf/jmxremote.password"
cp "$JAVA_HOME/jre/lib/management/jmxremote.access" "$CATALINA_BASE/conf/jmxremote.access"

jmxremote.password 用於設置各個【用戶名|密碼】

### $CATALINA_BASE/conf/jmxremote.password
jmxadmin    jmxpwd

jmxremote.access 用於設置各個【用戶名|權限】

### $CATALINA_BASE/conf/jmxremote.access
jmxadmin    readwrite \
            create javax.management.monitor.*,javax.management.timer.* \
            unregister

3.2.2 修改用戶驗證文件權限

安全起見,JMX 限制其他用戶不可讀這兩個用戶驗證文件。
默認情況下,Windows/Linux 下分別會報如下錯誤:

  • 錯誤: 必須限制口令文件讀取訪問權限: %CATALINA_BASE%\conf\jmxremote.password

  • Error: Password file read access must be restricted: $CATALINA_BASE/conf/jmxremote.password

Windows下可按如下操作修改文件權限:

  • 右鍵單擊文件 jmxremote.password,彈出菜單中選“屬性”,再點“安全”/“高級”/“更改權限”/“包括可從該對象的父項繼承的權限”(彈出窗口中選“刪除”以刪除所有訪問權限);

  • 再選“添加”/“高級”/“立即查找”,選中你的用戶(如 WKF-PC),點“確定”;

  • 權限項目窗口中勾選“完全控制”,點“確定”。

Linux 下則更簡單:

cd $CATALINA_BASE/confchmod 600 jmxremote.password jmxremote.access

3.2.3 修改 Tomcat 啓動時 JVM 選項

如果測試服務器無需開啓用戶驗證,只需修改下面參數 authenticate=false, 並去掉 password.file 和 access.file 兩個參數。

### Windows: %CATALINA_HOME%\bin\startup.bat
set JAVA_OPTS=%JAVA_OPTS% -Djava.rmi.server.hostname=%JMX_HOSTNAME% ^
    -Dcom.sun.management.jmxremote=true ^
    -Dcom.sun.management.jmxremote.port=1090 ^
    -Dcom.sun.management.jmxremote.ssl=false ^
    -Dcom.sun.management.jmxremote.authenticate=true ^
    -Dcom.sun.management.jmxremote.password.file=%CATALINA_BASE%\conf\jmxremote.password ^
    -Dcom.sun.management.jmxremote.access.file=%CATALINA_BASE%\conf\jmxremote.access
    
### Linux: $CATALINA_HOME/bin/startup.sh
export JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=$JMX_HOSTNAME
    -Dcom.sun.management.jmxremote=true-Dcom.sun.management.jmxremote.port=1090
    -Dcom.sun.management.jmxremote.ssl=false
    -Dcom.sun.management.jmxremote.authenticate=true
    -Dcom.sun.management.jmxremote.password.file=$CATALINA_BASE/conf/jmxremote.password
    -Dcom.sun.management.jmxremote.access.file=$CATALINA_BASE/conf/jmxremote.access"

3.3 開啓 jstatd agent(默認端口 1099)

### $CATALINA_BASE/conf/jstatd.policy
### 可借鑑 $JAVA_HOME/jre/lib/security/java.policy
grant codeBase "file:${java.home}/../lib/tools.jar" {
    permission java.security.AllPermission;
};
### $CATALINA_HOME/bin/jstatd.sh
### chmod +x $CATALINA_HOME/bin/jstatd.sh
#!/bin/sh

PID=`jps | grep Jstatd | awk '{print $1}'`
if [ -n "$PID" ]; then
    echo "kill -9 $PID ..."
    kill -9 $PID
fi

jstatd -J-Djava.rmi.server.hostname=$JMX_HOSTNAME \
-J-Djava.security.policy=$CATALINA_BASE/conf/jstatd.policy \
-J-Xms128M -J-Xmx128M -J-XX:NewRatio=1 -J-XX:SurvivorRatio=8 -J-XX:PermSize=16M -J-XX:MaxPermSize=16M \
< /dev/null &> $CATALINA_BASE/logs/jstatd.log &





3.4 配置防火牆(放行端口 1090/1099)

### /etc/sysconfig/iptables
-A INPUT -m state --state NEW -m tcp -p tcp --dport 1090 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 1099 -j ACCEPT
### 重啓生效: systemctl restart iptables


4 可視化工具


4.1 JConsole

早期的 Java 故障和監控工具,現在可以由強大的 VisualVM 代替。

4.2 VisualVM

4.2.1 文檔

http://m.blog.csdn.net/article/details?id=51090115
http://docs.oracle.com/javase/8/docs/technotes/guides/visualvm/index.html

4.2.2 下載與安裝

可以使用 JDK 自帶的 %JAVA_HOME%\bin\jvisualvm.exe;
也可以使用最新版本,下載方法如下:
下載頁:https://visualvm.github.io/download.html
主程序:https://github.com/visualvm/visualvm.src/releases/download/1.3.9/visualvm_139.zip
漢化包:https://github.com/visualvm/visualvm.src/releases/download/1.3.9/visualvm_139-ml.zip
IDE插件:https://visualvm.github.io/idesupport.html
主程序與漢化包解壓到同一目錄,最終主程序爲 bin\visualvm.exe;
IDE插件支持 Eclipse/IntelliJ IDEA,可以隨着 IDE 啓動。

4.2.3 安裝 VisualGC 插件

http://www.oracle.com/technetwork/java/visualgc-136680.html
VisualVM 中,點擊菜單“工具”/“插件”,如下圖安裝:

有些插件不能成功安裝,可下載 nbm 包再手工安裝:
https://visualvm.github.io/plugins.html
http://visualvm.java.net/pluginscenters.html
或者在插件設置裏,修改或新增插件源(pluginscenters.html裏點擊後能找到),再安裝。
http://bits.netbeans.org/VisualVM/uc/release138/updates.xml
http://bits.netbeans.org/VisualVM/uc/8u40/updates.xml
幾款有用的插件:

  • BTrace Workbench(只適用於本地應用): 用於不停止進程的情況下添加代碼跟蹤,入口在應用的右鍵菜單裏;

  • KillApplication(只適用於本地應用): 用於殺掉進程,入口在應用的右鍵菜單裏;

  • VisualVM-MBeans(本地和遠程通用):類似於 JConsole 展示應用的 MBean,包括值、操作、通知等;

  • Tracer(本地和遠程通用): 以時間曲線圖展示多種指標,包括CPU/GC/Heap/PermGen/Classes/Threads等。

4.2.4 前提條件

對於本地應用,VisualVM 所有功能直接支持它;
對於遠程應用,VisualGC 標籤頁要求服務端開啓 jstatd agent,其他標籤頁要求開啓 JMX,否則會顯示錯誤“不受此 JVM 支持”。
對於遠程應用,需要注意的是,服務端 jstatd/JMX 重啓後,VisualVM 必須重啓或者重建 JMX 連接,否則服務端調整在 VisualVM 中不生效。

4.2.5 添加遠程主機 / JMX連接

(1)添加“遠程主機”,指定遠程服務器的 IP 和 jstatd 端口:

(2)添加“JMX 連接”,指定遠程應用的 JMX 端口、用戶名和密碼:

4.2.6 監控遠程應用

(1)雙擊左側的“JMX 連接”(注意小圖標底部有 JMX 字樣),切換至“概述”標籤頁,可看到概述和 JVM 參數信息:

(2)切換至“監視”標籤頁,可看到 CPU、Heap、Class加載、線程等時間曲線圖:

(3)切換至“線程”標籤頁,可看到各線程 CPU 耗時統計:

(4)切換至“抽樣器”標籤頁,可看到熱點方法耗時、主要對象佔用空間統計(可用於定位內存泄露):

(5)切換至“VisualGC”標籤頁,可看到各種內存變化曲線、各GC時間點(可用於JVM參數調優):

4.2.7 JVM 優化實戰

(1)優化前,沒有明確指定各內存大小,使用 Java 默認內存大小,相當於指定爲:

export JAVA_OPTS="$JAVA_OPTS -Xms52M -Xmx244M -XX:NewRatio=2-XX:SurvivorRatio=8 -XX:PermSize=30M -XX:MaxPermSize=1G"

可見 YoungGC 很頻繁:


觀察圖形可得出以下優化方案:

  • 機器內存爲 1G,本應用爲系統唯一大應用,分給它 512M,另外 512M 預留給系統和其他應用;

  • 永久代只需 30M,可指定初始和最大值爲 64M,避免反覆伸縮的開銷;

  • 整個堆(新生代+老年代)目前內存爲 240M,可增加至 384M,指定初始和最大值都爲 384M,避免反覆伸縮的開銷;

  • YoungGC 過於頻繁,原因是 Eden 區過小。“老年代/新生代”目前比例爲 -XX:NewRatio=2,看圖形可知,老年代中長壽對象並不多,可縮減老年代讓給新生代,所以調整 -XX:NewRatio=1;

  • “Eden / Survivor0”比值目前爲 -XX:SurvivorRatio=8,暫不調整。

(2)優化後,指定 JVM 選項爲:

### Linux: $CATALINA_HOME/bin/startup.shexport JAVA_OPTS="$JAVA_OPTS -Xms384M -Xmx384M 
-XX:NewRatio=1-XX:SurvivorRatio=8 -XX:PermSize=64M -XX:MaxPermSize=64M"

可見 YoungGC 大幅減少:

(3)優化前後對比:
優化前:YoungGC 102次,總耗時 965ms, FullGC 5次,總耗時 240ms,而且應用穩定後 YoungGC 仍然反覆發生;
優化後:YoungGC 3次,總耗時 26ms, FullGC 1次,總耗時 4ms,而且應用穩定後 YoungGC 長期未再發生;
優化效果非常明顯。

5 命令行工具(服務端)

5.1 jps(查看Java進程)

### jps -vlm | grep Bootstrap
1162 ## 進程ID
    -Xms300M -Xmx300M -XX:NewRatio=2 -XX:SurvivorRatio=8 ## -v的作用,顯示 JVM 參數
    org.apache.catalina.startup.Bootstrap ## -l的作用,顯示主類的全名(或JAR包路徑)
    start ## -m 的作用,顯示傳遞給主類 main() 函數的參數

5.2 jmap/jhat(快照的生成與查看)

### 服務器上執行,生成 heapdump 快照文件
jmap -dump:live,format=b,file=tomcat.hprof 1162
sz tomcat.hprof ## 下載到個人PC

### 創建WEB服務,個人PC上可以用瀏覽器查看 http://localhost:8080/
### 功能較弱,以 package 分組展示,“Show heap histogram”可用於分析內存泄露。
### 也可以用 VisualVM 打開快照文件來查看
jhat -port 8080 tomcat.hprof

### jmap 更多功能
jmap -heap 1162 ## 查看堆內存劃分、各區塊尺寸、已用容量和比率等
jmap -histo:live 1162 ## 可用於排查內存泄露,查看堆中(僅存活的)各 class 的實例數、總佔用空間

5.3 jstack

jstack 1162 > jstack.log ## 可生成應用的各線程 StackTrace

5.4 jcmd

jcmd ## 類似於 jps,查看 java 進程
jcmd 1162 help ## 查看該進程支持的命令
jcmd 1162 VM.uptime ## 顯示啓動時間
jcmd 1162 VM.flags ## 顯示VM標誌
jcmd 1162 VM.version ## 查看虛擬機版本
jcmd 1162 VM.command_line ## 顯示命令行及參數
jcmd 1162 VM.system_properties ## 顯示系統屬性
jcmd 1162 GC.run ## 執行 System.gc()
jcmd 1162 GC.run_finalization ## 執行 System.runFinalization()
jcmd 1162 GC.class_histogram ## 相當於 jmap -histo:live 1162
jcmd 1162 GC.heap_dump tomcat.hprof ## 生成堆快照文件
jcmd 1162 Thread.print ## 相當於 jstack 1162
jcmd 1162 PerfCounter.print ## 顯示進程內各種計數器

6 開發監控系統

假設有個需求(這裏只是爲了演示,現實中不會這麼簡單粗暴,現實中還需要限制在凌晨才觸發):Heap 使用率高於 60%,就要求強制 FullGC。

6.1 Shell 腳本

PID=`jps | grep Bootstrap | awk '{print $1}'`

## 計算 Heap 使用率
## 下面命令會輸出 Eden/S0/S1/Tenured 各自的總空間和已用空間,很容易算出 Heap 使用率:
## used(Eden+S0+S1+Tenured)/total(Eden+S0+S1+Tenured)# jstat -gc $PID
## 判斷使用率大於 60% 才執行 FullGCjcmd $PID GC.run

6.2 Java 代碼

代碼中使用的“java.lang:type=Memory”、“HeapMemoryUsage”可以藉助 VisualVM/MBeans插件的 Attribtes/Operations 標籤頁中找到,如下圖:

package wang.kefeng.JmxAdmin;
import java.lang.management.MemoryUsage;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * @author http://kefeng.wang
 * @date 2016-11-24 20:20:08
 */
public class App {
    private static final String JMX_HOSTNAME = "192.168.214.128:1090";
    private static final String JMX_USERNAME = "jmxadmin";
    private static final String JMX_PASSWORD = "jmxpwd";
    private static final Logger logger = LoggerFactory.getLogger(App.class);
    public static void main(String[] args) throws Exception {
        // 1.建立連接(mbsc)
        String jmxURL = "service:jmx:rmi:///jndi/rmi://" + JMX_HOSTNAME + "/jmxrmi";
        JMXServiceURL serviceURL = new JMXServiceURL(jmxURL);
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("jmx.remote.credentials", new String[] { JMX_USERNAME, JMX_PASSWORD });
        JMXConnector connector = JMXConnectorFactory.connect(serviceURL, map);
        MBeanServerConnection mbsc = connector.getMBeanServerConnection();
        // 2.獲取遠程應用數據
        ObjectName objectName = new ObjectName("java.lang:type=Memory");
        Object heapMemoryUsage = mbsc.getAttribute(objectName, "HeapMemoryUsage");
        MemoryUsage usage = MemoryUsage.from((CompositeDataSupport) heapMemoryUsage);
        // 示例:如果 Heap 使用率大於 60%,則請求 FullGC
        long usedRate = usage.getUsed() * 100 / usage.getMax();
        logger.info("usedRate={}, {} / {}", usedRate, usage.getUsed(), usage.getMax());
        if (usedRate > 30) {
            mbsc.invoke(objectName, "gc", null, null);
            logger.info("gc() OK.");
        }
        // 3.更多有用的 MBeans
        // (1)com.sun.management:type=HotSpotDiagnostic
        // dumpHeap(), getVMOption(), setVMOption()
        // (2)java.util.logging:type=Logging
        // getLoggerLevel(), setLoggerLevel()
    }
}




7 內存泄露插件

7.1 內存泄露現象

老年代越來越大,GC越來越頻繁、執行時間越來越長,而且GC後內存未釋放。

7.2 生成快照文件(hprof Heap信息文件)

  • 使用Java的jmap命令來生成;

  • 通過JMX的MBean用Java代碼生成;

7.3 分析dump文件

  • 最佳方案是使用 Eclipse MAT 插件;

  • 其他候選方案:Java 自帶工具 Visual VM / jhat、IBM HeapAnalyzer;

7.4 分析內存泄漏

可看到可疑的內存泄露對象,看到佔用空間大的對象及其調用關係。

8 GC日誌

8.1 開啓gc日誌文件

### Linux: $CATALINA_HOME/bin/startup.sh
export JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDateStamps -XX:+PrintGCDetails
-XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -Xloggc:$CATALINA_BASE/logs/gc.log"


[停頓類型
8.2 日誌文件格式解析

  [新生代: GC前本區域已用容量 -> GC後本區域已用容量 (本區域總容量), 本區域GC耗時]
  [老年代: GC前本區域已用容量 -> GC後本區域已用容量 (本區域總容量), 本區域GC耗時]
    GC前Heap已用容量 -> GC後Heap已用容量 (Heap總容量)
  [永久代: GC前本區域已用容量 -> GC後本區域已用容量 (本區域總容量), 本區域GC耗時]
  [Times: 用戶耗時=xx 系統耗時=yy, 實際耗時=zz secs]

==== server 模式的 GC+FullGC ====
新生代:PSYoungGen=Parallel Scavenge
老年代:ParOldGen=Parallel Old
永久代:PSPermGen

[GC
    [PSYoungGen: 6980K->600K(9216K)]
    6980K->6744K(19456K), 0.0028901 secs]
    [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC
    [PSYoungGen: 600K->0K(9216K)]
    [ParOldGen: 6144K->6617K(10240K)]
    6744K->6617K(19456K)
    [PSPermGen: 2567K->2566K(21504K)], 0.0095238 secs]
    [Times: user=0.02 sys=0.00, real=0.02 secs]




==== client 模式的 GC+FullGC ====
新生代:DefNew=Serial(Default New Generation)
老年代:Tenured
永久代:Perm

[GC
    [DefNew: 6871K->382K(9216K), 0.0037941 secs]
    [Tenured: 6144K->6525K(10240K), 0.0033262 secs]
    6871K->6525K(19456K),
    [Perm : 186K->186K(12288K)], 0.0081090 secs]
    [Times: user=0.00 sys=0.00, real=0.00 secs]

[Full GC
    [Tenured: 6525K->6514K(10240K), 0.0026225 secs]
    6525K->6514K(19456K),
    [Perm : 186K->186K(12288K)], 0.0028221 secs]
    [Times: user=0.00 sys=0.00, real=0.00 secs]




=================================

8.3 gc.log 解析工具

8.3.1 在線分析

http://gceasy.io/

8.3.2 ga456(IBM)

https://www.ibm.com/developerworks/community/alphaworks/tech/pmat
ftp://public.dhe.ibm.com/software/websphere/appserv/support/tools/pmat/ga456.jar

8.3.3 HPjmeter

https://h20392.www2.hpe.com/portal/swdepot/displayProductInfo.do?productNumber=HPJMETERSW
需要註冊帳號並登錄,最終下載頁中選擇“Use Standard Download”,Windows上可下載這兩個:
MS Windows XP/Vista/7 HPjmeter 4.4.00.00 Console - Oct 2014 (Z7550-01611_hpjmeter_console_4.4.00.00_windows_setup.exe)
HPjmeter 4.4.00.00 Console jar file zip format - Feb 2015 (Z7550-63266_hpjmeter_4.4.00.00.zip)

8.3.4 GCViewer

http://www.tagtraum.com/gcviewer.html
http://www.tagtraum.com/gcviewer-download.html
http://www.tagtraum.com/download/gcviewer-1.29-bin.zip

8.3.5 IBM GCMV(Eclipse 插件)

GCMV=Garbage Collection and Memory Visualizer
插件中心搜索 “GCMV” 來安裝,然後在菜單中打開: Window / Perspective / Open Perspective / GCMV

8.3.6 gchisto(VisualVM 插件)

https://gchisto.dev.java.net/
http://java.net/projects/gchisto
http://pietrowski.info/wp-content/uploads/2009/06/GCHisto.tgz

8.3.7 其他更多

https://code.google.com/archive/p/gclogviewer/
https://code.google.com/archive/p/verbosegcanalyzer
http://fasterj.com/tools/gcloganalysers.shtml
http://techblog.netflix.com/2013/05/garbage-collection-visualization.html


原文鏈接:https://kefeng.wang/2016/11/22/java-jvm/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章