FULL PRODUCT VERSION : java version "1.7.0" Java(TM) SE Runtime Environment (build 1.7.0-b147) Java HotSpot(TM) 64-Bit Server VM (build 21.0-b17, mixed mode) FULL OS VERSION : ALL (OS independent issue). A DESCRIPTION OF THE PROBLEM : When grabbing GarbageCollectorMXBean from the ManagementFactory, it is NOW possible (in Java 7) to cast the underlying bean implementation into a NotificationBroadcaster and add a NotificationListener. Doing this causes the JVM to report on GC events after they're done. In the JVM, GCNotifier::pushNotification puts the "raw" GCStatInfo data (containing start/end ticks) onto the request queue. GCNotifier::sendNotification constructs GcInfo from this data WITHOUT converting the ticks to millis. When the listener gets access to the GcInfo object, a call to getDuration() returns elapsed ticks vs. elapsed millis (contrary to comments in the source code). This all constrasts the notion of calling GarbageCollectorMXBean.getLastGcInfo, which under the covers DOES convert the ticks to millis prior to returning the object. THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: Did not try THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Did not try STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : Use the provided source code. EXPECTED VERSUS ACTUAL BEHAVIOR : Actual results: PS Scavenge : 7093839093246673821 PS Scavenge : 4309 PS Scavenge : 4305 PS Scavenge : 4304 PS Scavenge : 3037 PS Scavenge : 3226 PS Scavenge : 2991 PS Scavenge : 4432 PS Scavenge : 1643 PS Scavenge : 1797 PS Scavenge : 973 PS Scavenge : 863 PS Scavenge : 738 PS Scavenge : 993 PS Scavenge : 765 ... REPRODUCIBILITY : This bug can be reproduced always. ---------- BEGIN SOURCE ---------- public static void main(String[] args) { NotificationListener nl = new NotificationListener() { @Override public void handleNotification(Notification notification, Object name) { CompositeData cd = (CompositeData) notification.getUserData(); cd = (CompositeData) cd.get("gcInfo"); GcInfo gcInfo = GcInfo.from(cd); long ticksNotMillis = gcInfo.getDuration(); System.out.append(String.valueOf(name)).append(" : "); System.out.append(Long.toString(ticksNotMillis)).append("\n"); } }; List<GarbageCollectorMXBean> list = ManagementFactory.getGarbageCollectorMXBeans(); for (GarbageCollectorMXBean bean : list) ((NotificationBroadcaster) bean).addNotificationListener(nl, null, bean.getName()); // Force garbage collection long start = System.currentTimeMillis(); for (;;) { long now = System.currentTimeMillis(); if (now - start > 5000) break; byte[] bytes = new byte[1048576]; } } ---------- END SOURCE ----------
|