如何从应用程序内部检测 JVM 垃圾收集周期?
How to detect JVM Garbage Collection cycle from INSIDE the app?
我只是想知道是否有一种方法可以从正在 gc 的 code/JVM 中检测垃圾收集周期。
时机不起作用。因此,事件是发生在实际周期之前还是之后并不重要。 (在循环期间发生事件似乎极不可能,而且可能也很危险,具体取决于所使用的 GC 实现)。
我只能找到可以与 运行 JVM 并行使用的应用程序,例如 jstat:https://dzone.com/articles/how-monitor-java-garbage with the source code here, for example: https://github.com/eagle518/jdk-source-code/blob/master/jdk5.0_src/j2se/src/share/classes/sun/tools/jstat/Jstat.java
我只看到他们用
MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(vmId);
MonitoredVm monitoredVm = monitoredHost.getMonitoredVm(vmId, interval);
所以我的问题是基于 2 个问题。如果第二个问题有解,我们就不用回答问题1了:
- 我对MonitoredVm的了解还不够,不知道如何访问本地JVM。通常需要 VM ID。我怎样才能可靠地解决这个问题,或者有其他方法可以获得 'local'
MonitoredVm
?
- 是否有必要使用 MonitoredVm,或者是否有更简单的方法,例如可以 'install' 关闭挂钩并检测该事件 (
Runtime.getRuntime().addShutdownHook(hookThread);
)? Java反思也是一个受欢迎的解决方案!
至少 count(和累计时间)的垃圾收集是通过 JMX MBeans 公开的。
特别是 ManagementFactory.getGarbageCollectorMXBeans()
will return a list of GarbageCollectorMXBean
提供 getCollectionCount()
方法的对象。您可以轮询这些值并对它们的变化做出反应。
GarbageCollectorMXBean
is pointing into the right direction. What’s not obvious, is that this bean implements NotificationEmitter
允许有关垃圾回收的通知:
static volatile Object PREVENT_ESCAPE_ANALYSIS;
public static void main(String[] args) {
List<GarbageCollectorMXBean> gc = ManagementFactory.getGarbageCollectorMXBeans();
for(GarbageCollectorMXBean b: gc) {
((NotificationEmitter)b).addNotificationListener((n, handback) -> {
GarbageCollectionNotificationInfo gcni
= GarbageCollectionNotificationInfo.from((CompositeData)n.getUserData());
GcInfo info = gcni.getGcInfo();
System.out.printf("%tT.%1$tL %dms %s %s %s%n", info.getStartTime(),
info.getDuration(),gcni.getGcName(),gcni.getGcAction(),gcni.getGcCause());
Map<String, MemoryUsage> before = info.getMemoryUsageBeforeGc();
info.getMemoryUsageAfterGc().forEach((s, u) -> {
long bu = before.get(s).getUsed(), au = u.getUsed();
if(bu != au) System.out.println("\t" + s + " " + bu + " -> " + au);
});
}, null, b);
}
for(;;) {
PREVENT_ESCAPE_ANALYSIS = new Object();
}
}
Demo on Ideone
00:00:00.203 2ms Copy end of minor GC Allocation Failure
Eden Space 70516736 -> 0
Survivor Space 0 -> 795176
00:00:00.271 1ms Copy end of minor GC Allocation Failure
Eden Space 70516736 -> 0
Survivor Space 795176 -> 862960
00:00:00.355 2ms Copy end of minor GC Allocation Failure
Eden Space 70516736 -> 0
Survivor Space 862960 -> 931952
00:00:00.412 2ms Copy end of minor GC Allocation Failure
Eden Space 70516736 -> 0
Survivor Space 931952 -> 1004784
00:00:00.497 2ms Copy end of minor GC Allocation Failure
Eden Space 70516736 -> 0
Survivor Space 1004784 -> 1379400
00:00:00.574 3ms Copy end of minor GC Allocation Failure
Eden Space 70516736 -> 0
Survivor Space 1379400 -> 1551944
00:00:00.632 2ms Copy end of minor GC Allocation Failure
Eden Space 70516736 -> 0
Survivor Space 1551944 -> 1541144
…
我只是想知道是否有一种方法可以从正在 gc 的 code/JVM 中检测垃圾收集周期。
时机不起作用。因此,事件是发生在实际周期之前还是之后并不重要。 (在循环期间发生事件似乎极不可能,而且可能也很危险,具体取决于所使用的 GC 实现)。
我只能找到可以与 运行 JVM 并行使用的应用程序,例如 jstat:https://dzone.com/articles/how-monitor-java-garbage with the source code here, for example: https://github.com/eagle518/jdk-source-code/blob/master/jdk5.0_src/j2se/src/share/classes/sun/tools/jstat/Jstat.java
我只看到他们用
MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(vmId);
MonitoredVm monitoredVm = monitoredHost.getMonitoredVm(vmId, interval);
所以我的问题是基于 2 个问题。如果第二个问题有解,我们就不用回答问题1了:
- 我对MonitoredVm的了解还不够,不知道如何访问本地JVM。通常需要 VM ID。我怎样才能可靠地解决这个问题,或者有其他方法可以获得 'local'
MonitoredVm
? - 是否有必要使用 MonitoredVm,或者是否有更简单的方法,例如可以 'install' 关闭挂钩并检测该事件 (
Runtime.getRuntime().addShutdownHook(hookThread);
)? Java反思也是一个受欢迎的解决方案!
至少 count(和累计时间)的垃圾收集是通过 JMX MBeans 公开的。
特别是 ManagementFactory.getGarbageCollectorMXBeans()
will return a list of GarbageCollectorMXBean
提供 getCollectionCount()
方法的对象。您可以轮询这些值并对它们的变化做出反应。
GarbageCollectorMXBean
is pointing into the right direction. What’s not obvious, is that this bean implements NotificationEmitter
允许有关垃圾回收的通知:
static volatile Object PREVENT_ESCAPE_ANALYSIS;
public static void main(String[] args) {
List<GarbageCollectorMXBean> gc = ManagementFactory.getGarbageCollectorMXBeans();
for(GarbageCollectorMXBean b: gc) {
((NotificationEmitter)b).addNotificationListener((n, handback) -> {
GarbageCollectionNotificationInfo gcni
= GarbageCollectionNotificationInfo.from((CompositeData)n.getUserData());
GcInfo info = gcni.getGcInfo();
System.out.printf("%tT.%1$tL %dms %s %s %s%n", info.getStartTime(),
info.getDuration(),gcni.getGcName(),gcni.getGcAction(),gcni.getGcCause());
Map<String, MemoryUsage> before = info.getMemoryUsageBeforeGc();
info.getMemoryUsageAfterGc().forEach((s, u) -> {
long bu = before.get(s).getUsed(), au = u.getUsed();
if(bu != au) System.out.println("\t" + s + " " + bu + " -> " + au);
});
}, null, b);
}
for(;;) {
PREVENT_ESCAPE_ANALYSIS = new Object();
}
}
Demo on Ideone
00:00:00.203 2ms Copy end of minor GC Allocation Failure
Eden Space 70516736 -> 0
Survivor Space 0 -> 795176
00:00:00.271 1ms Copy end of minor GC Allocation Failure
Eden Space 70516736 -> 0
Survivor Space 795176 -> 862960
00:00:00.355 2ms Copy end of minor GC Allocation Failure
Eden Space 70516736 -> 0
Survivor Space 862960 -> 931952
00:00:00.412 2ms Copy end of minor GC Allocation Failure
Eden Space 70516736 -> 0
Survivor Space 931952 -> 1004784
00:00:00.497 2ms Copy end of minor GC Allocation Failure
Eden Space 70516736 -> 0
Survivor Space 1004784 -> 1379400
00:00:00.574 3ms Copy end of minor GC Allocation Failure
Eden Space 70516736 -> 0
Survivor Space 1379400 -> 1551944
00:00:00.632 2ms Copy end of minor GC Allocation Failure
Eden Space 70516736 -> 0
Survivor Space 1551944 -> 1541144
…