2

I just wondered if there's a way to detect a Garbage Collection cycle from within the code/JVM that's being gc'd.

Timing does not play a role. So whether it's an event that occurs sometime before the actual cycle or afterwards is not important. (Having an event DURING the cycle seems highly unlikely and is probably dangerous too, depending on the GC implementation used).

All I could find were apps that can be used in parallel to the running JVM, such as 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

All I see is that they use

 MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(vmId); MonitoredVm monitoredVm = monitoredHost.getMonitoredVm(vmId, interval); 

So my problem is based on 2 questions. If the second question has a solution, we don't need to answer Q 1:

  1. my knowledge of MonitoredVm is not not good enough to know how to access the local JVM. Usually there's the VM ID required. How could I address that reliably, or is there another way that I can get the 'local' MonitoredVm?
  2. and would it even be necessary to use MonitoredVm, or is there anything a lot easier, like one can 'install' a shutdown hook and detect that event (Runtime.getRuntime().addShutdownHook(hookThread);)? Java Reflection is also a welcome solution!
2
  • There's no actual problem I wanna solve. It's just a theoretical thought. If you have arrays/ArrayLists/HashSets that may grow quite large (simulations with grid logic and lots of moving objects) but the objects also get removed a lot, at some point you wanna shrink them back. You could check that on every removal, but later on it might need to grow in size again. So I thought the GC cycles might be a good indicator of when to check for RAM reaching limits, and then resize the lists with the worst size-to-elements ratio. But if I need polling, I could also just poll the RAM statistics... Commented Nov 15, 2021 at 12:07
  • I know none such data structures. Commented Nov 15, 2021 at 13:05

2 Answers 2

6

GarbageCollectorMXBean is pointing into the right direction. What’s not obvious, is that this bean implements NotificationEmitter which allows notifications about garbage collections:

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 … 
Sign up to request clarification or add additional context in comments.

2 Comments

Hehe BTW your log sounds so negative... "Copy end of minor GC Allocation Failure". My GraalVM Java 11 sounds a bit more informative: "01:00:01.646 4ms G1 Young Generation end of minor GC G1 Evacuation Pause" :-D
Actually, the log on my machine looked better than this, too. It’s the machine of Ideone (resp. their configured GC algorithm) that produces these strings. When I saw that, I considered putting stronger separators between the strings, but then dropped that thought, as it is just simple example code anyway… Note that “GC Allocation Failure” is the name of the event that triggered GC and typical for non-concurrent GCs, as they only start their work when an allocation failed.
3

At least the count (and accumulated time) of garbage collection is exposed via JMX MBeans.

Specifically ManagementFactory.getGarbageCollectorMXBeans() will return a list of GarbageCollectorMXBean objects providing a getCollectionCount() method. You could poll those values and react to them changing.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.