2 回答

TA貢獻1854條經驗 獲得超8個贊
jcmd <pid> VM.flags應該有幫助。
例如
$ /usr/java/jdk1.8.0_202/bin/java Test
...
$ jcmd 28815 VM.flags
28815:
-XX:CICompilerCount=3 -XX:InitialHeapSize=266338304 -XX:MaxHeapSize=4257218560 -XX:MaxNewSize=1418723328 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=88604672 -XX:OldSize=177733632 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
最后打印的標志-XX:+UseParallelGC即使沒有明確指定。
然后,如果我運行將 G1 作為默認收集器的 JDK 11,我將得到以下輸出:
$ /usr/java/jdk11.0.2/bin/java Test
...
$ jcmd 28862 VM.flags
28862:
-XX:CICompilerCount=3 -XX:ConcGCThreads=1 -XX:G1ConcRefinementThreads=4 -XX:G1HeapRegionSize=1048576 -XX:GCDrainStackTargetSize=64 -XX:InitialHeapSize=266338304 -XX:MarkStackSize=4194304 -XX:MaxHeapSize=4257218560 -XX:MaxNewSize=2554331136 -XX:MinHeapDeltaBytes=1048576 -XX:NonNMethodCodeHeapSize=5830092 -XX:NonProfiledCodeHeapSize=122914074 -XX:ProfiledCodeHeapSize=122914074 -XX:ReservedCodeCacheSize=251658240 -XX:+SegmentedCodeCache -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseG1GC
現在最后打印的選項是-XX:+UseG1GC.
如果由于某種原因你沒有jcmd可用的,你可以嘗試jattach哪個是輕量級的獨立替代品jcmd:
$ jattach 28862 jcmd VM.flags
更新
如果沒有-XX:Use*GC打印任何標志,則表示使用了 Serial GC。這只發生在 JDK 8 和更早版本上。從 JDK 9 開始,Use*GCJVM 會自動設置其中一個標志。有關詳細信息,請參閱JDK-8068582。

TA貢獻1780條經驗 獲得超4個贊
bool問題是,當您真正想要一個名稱時,您正在查看類型的 JVM 選項。這不是你的錯,JVM 的設計者決定給不同的垃圾收集器命名,但提供看起來像布爾選項的控件。
因此,即使所有這些選項都是false,也有一個垃圾收集器,但這些選項不足以獲得它的名字。但另一方面,無論如何,大多數名稱都不足以描述這些垃圾收集器的作用,或者它們與其他算法的不同之處。
JDK8默認使用ParallelGC并不完全正確;正如這個答案所描述的,該算法是由一些啟發式選擇的,但是,在大多數情況下,你最終會選擇 ParallelGC。
使用以下代碼
Object flags = ManagementFactory.getPlatformMBeanServer().invoke(
ObjectName.getInstance("com.sun.management:type=DiagnosticCommand"),
"vmFlags", new Object[] { null }, new String[] { "[Ljava.lang.String;" });
for(String f: ((String)flags).split("\\s+"))
if(f.contains("GC")) System.out.println(f);
for(GarbageCollectorMXBean gc: ManagementFactory.getGarbageCollectorMXBeans())
System.out.printf("%-20s%s%n", gc.getName(), Arrays.toString(gc.getMemoryPoolNames()));
我明白了
> jdk1.8.0_162\bin\java ...
-XX:+UseParallelGC
PS Scavenge [PS Eden Space, PS Survivor Space]
PS MarkSweep [PS Eden Space, PS Survivor Space, PS Old Gen]
在我的機器上,所以在沒有選項的情況下運行確實在這個環境中選擇了 ParallelGC。但請注意報告的名稱“PS Scavenge”和“PS MarkSweep”,它們突出了選項和名稱的另一個問題:典型配置考慮有兩種垃圾收集算法,一種用于次要 gc,一種用于主要 gc。
當我嘗試時-XX:-UseParallelGC,我得到
> jdk1.8.0_162\bin\java -XX:-UseParallelGC ...
-XX:+UseParallelGC
PS Scavenge [PS Eden Space, PS Survivor Space]
PS MarkSweep [PS Eden Space, PS Survivor Space, PS Old Gen]
這演示了 JVM 選項的問題,如下所示boolean:我無法關閉它們,因為 JVM 需要一個實際的其他垃圾收集器來選擇。
所以要關閉并行,你可以使用-XX:+UseSerialGC:
> jdk1.8.0_162\bin\java -XX:+UseSerialGC ...
-XX:+UseSerialGC
Copy [Eden Space, Survivor Space]
MarkSweepCompact [Eden Space, Survivor Space, Tenured Gen]
為了比較
> jdk1.8.0_162\bin\java -XX:+UseConcMarkSweepGC ...
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
ParNew [Par Eden Space, Par Survivor Space]
ConcurrentMarkSweep [Par Eden Space, Par Survivor Space, CMS Old Gen]
請注意這兩種算法中的每一種如何與一個選項相關聯,但指定一個選項可以選擇兩種垃圾收集算法。
> jdk-9.0.4\bin\java ...
-XX:ConcGCThreads=2
-XX:+UseG1GC
G1 Young Generation [G1 Eden Space, G1 Survivor Space]
G1 Old Generation [G1 Eden Space, G1 Survivor Space, G1 Old Gen]
> jdk-11.0.1\bin\java ...
-XX:ConcGCThreads=2
-XX:GCDrainStackTargetSize=64
-XX:+UseG1GC
G1 Young Generation [G1 Eden Space, G1 Survivor Space, G1 Old Gen]
G1 Old Generation [G1 Eden Space, G1 Survivor Space, G1 Old Gen]
> jdk-11.0.1\bin\java -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC ...
-XX:+UseEpsilonGC
Epsilon Heap [Epsilon Heap]
因此,如果嘗試獲取相關Use…GC boolean選項的代碼(即上面代碼的第一部分,使用非標準com.sun.management:type=DiagnosticCommandMBean)找不到任何選項,您可以嘗試使用 報告的垃圾收集器名稱getGarbageCollectorMXBeans(),但正如您所見,這些名稱與 JVM 選項的名稱不匹配,因此您必須知道這些名稱是如何關聯的。
但歸根結底,這些名稱都不是真正的描述性名稱,所以它們只有在您已經知道這些名稱背后的內容時才有用……
添加回答
舉報