|
26 | 26 | import java.util.HashMap; |
27 | 27 | import java.util.Map; |
28 | 28 | import java.util.concurrent.TimeUnit; |
| 29 | +import java.util.concurrent.atomic.AtomicLong; |
29 | 30 | import java.util.concurrent.atomic.AtomicReference; |
30 | 31 |
|
31 | 32 | import javax.management.MBeanServer; |
@@ -54,36 +55,34 @@ public class GCInspector implements NotificationListener, GCInspectorMXBean |
54 | 55 |
|
55 | 56 | /* |
56 | 57 | * The field from java.nio.Bits that tracks the total number of allocated |
57 | | - * bytes of direct memory requires via ByteBuffer.allocateDirect that have not been GCed. |
| 58 | + * bytes of direct memory requested via ByteBuffer.allocateDirect that have not been GCed. |
58 | 59 | */ |
59 | | - final static Field BITS_TOTAL_CAPACITY; |
| 60 | + final static Field BITS_TOTAL_CAPACITY_JAVA_8; |
| 61 | + final static Field BITS_TOTAL_CAPACITY_JAVA_11; |
60 | 62 |
|
61 | | - |
62 | 63 | static |
63 | 64 | { |
64 | | - Field temp = null; |
| 65 | + Class<?> bitsClass = null; |
| 66 | + |
65 | 67 | try |
66 | 68 | { |
67 | | - Class<?> bitsClass = Class.forName("java.nio.Bits"); |
68 | | - Field f; |
69 | | - try |
70 | | - { |
71 | | - f = bitsClass.getDeclaredField("totalCapacity"); |
72 | | - } |
73 | | - catch (NoSuchFieldException ex) |
74 | | - { |
75 | | - // in Java11 it changed name to "TOTAL_CAPACITY" |
76 | | - f = bitsClass.getDeclaredField("TOTAL_CAPACITY"); |
77 | | - } |
78 | | - f.setAccessible(true); |
79 | | - temp = f; |
| 69 | + bitsClass = Class.forName("java.nio.Bits"); |
80 | 70 | } |
81 | 71 | catch (Throwable t) |
82 | 72 | { |
83 | | - logger.debug("Error accessing field of java.nio.Bits", t); |
84 | | - //Don't care, will just return the dummy value -1 if we can't get at the field in this JVM |
| 73 | + logger.debug("Error returning class of java.nio.Bits", t); |
| 74 | + } |
| 75 | + |
| 76 | + if (bitsClass != null) |
| 77 | + { |
| 78 | + BITS_TOTAL_CAPACITY_JAVA_8 = getField(bitsClass, "totalCapacity"); |
| 79 | + BITS_TOTAL_CAPACITY_JAVA_11 = getField(bitsClass, "TOTAL_CAPACITY"); |
| 80 | + } |
| 81 | + else |
| 82 | + { |
| 83 | + BITS_TOTAL_CAPACITY_JAVA_8 = null; |
| 84 | + BITS_TOTAL_CAPACITY_JAVA_11 = null; |
85 | 85 | } |
86 | | - BITS_TOTAL_CAPACITY = temp; |
87 | 86 | } |
88 | 87 |
|
89 | 88 | static final class State |
@@ -324,14 +323,47 @@ public double[] getAndResetStats() |
324 | 323 |
|
325 | 324 | private static long getAllocatedDirectMemory() |
326 | 325 | { |
327 | | - if (BITS_TOTAL_CAPACITY == null) return -1; |
| 326 | + long fieldValue = getFieldValue(BITS_TOTAL_CAPACITY_JAVA_8, true); |
| 327 | + |
| 328 | + if (fieldValue == -1) |
| 329 | + fieldValue = getFieldValue(BITS_TOTAL_CAPACITY_JAVA_11, true); |
| 330 | + |
| 331 | + return fieldValue; |
| 332 | + } |
| 333 | + |
| 334 | + private static Field getField(Class<?> clazz, String fieldName) |
| 335 | + { |
| 336 | + try |
| 337 | + { |
| 338 | + Field field = clazz.getDeclaredField(fieldName); |
| 339 | + field.setAccessible(true); |
| 340 | + return field; |
| 341 | + } |
| 342 | + catch (Throwable t) |
| 343 | + { |
| 344 | + logger.trace("Error accessing field {} of {}", fieldName, clazz.getName(), t); |
| 345 | + // Return null to indicate failure |
| 346 | + return null; |
| 347 | + } |
| 348 | + } |
| 349 | + |
| 350 | + /** |
| 351 | + * Retrieves the value of a Field, handling both regular long fields and AtomicLong fields. |
| 352 | + * |
| 353 | + * @param field the Field to retrieve the value from |
| 354 | + * @param isAtomicLong true if the field is an AtomicLong, false if it's a regular long |
| 355 | + * @return the field value, or -1 if retrieval fails or field is null. |
| 356 | + */ |
| 357 | + private static long getFieldValue(Field field, boolean isAtomicLong) |
| 358 | + { |
| 359 | + if (field == null) return -1; |
328 | 360 | try |
329 | 361 | { |
330 | | - return BITS_TOTAL_CAPACITY.getLong(null); |
| 362 | + return isAtomicLong ? ((AtomicLong) field.get(null)).get() : field.getLong(null); |
331 | 363 | } |
332 | 364 | catch (Throwable t) |
333 | 365 | { |
334 | | - logger.trace("Error accessing field of java.nio.Bits", t); |
| 366 | + logger.trace("Error accessing field value of {}", field.getName(), t); |
335 | 367 | //Don't care how or why we failed to get the value in this JVM. Return -1 to indicate failure |
336 | 368 | return -1; |
337 | 369 | } |
|
0 commit comments