|
1 | 1 | package jvm_alloc_rate_meter;
|
2 | 2 |
|
3 | 3 | import com.sun.management.ThreadMXBean;
|
| 4 | +import java.math.BigInteger; |
4 | 5 | import java.util.function.LongConsumer;
|
5 | 6 | import java.lang.management.GarbageCollectorMXBean;
|
6 | 7 | import java.lang.management.ManagementFactory;
|
@@ -34,24 +35,26 @@ public MeterThread(LongConsumer callback, int intervalMs) {
|
34 | 35 | // one if it did.
|
35 | 36 |
|
36 | 37 | public void run() {
|
37 |
| - long lastTime = 0, lastHeapUsage = -1, lastGcCounts = -1, lastThreadAllocated = -1; |
| 38 | + long lastTime = 0, lastHeapUsage = -1, lastGcCounts = -1; |
| 39 | + BigInteger lastThreadAllocated = BigInteger.valueOf(-1); |
38 | 40 | try {
|
39 | 41 | while (doRun) {
|
40 | 42 | long heapUsage = usedHeap();
|
41 | 43 | long gcCounts = gcCounts();
|
42 |
| - long threadAllocated = allocatedByAllThreads(); |
| 44 | + BigInteger threadAllocated = allocatedByAllThreads(); |
43 | 45 | long time = System.currentTimeMillis();
|
44 | 46 |
|
45 | 47 | double multiplier = 1000.0 / (time - lastTime);
|
46 | 48 | long deltaUsage = heapUsage - lastHeapUsage;
|
47 |
| - long deltaThreadAllocated = threadAllocated - lastThreadAllocated; |
48 | 49 |
|
49 | 50 | if (lastTime != 0) {
|
50 | 51 | if ((gcCounts == lastGcCounts) && (deltaUsage >= 0)) {
|
51 | 52 | long rate = Math.round(deltaUsage * multiplier);
|
52 | 53 | callback.accept(rate);
|
53 |
| - } else if (deltaThreadAllocated >= 0) { |
54 |
| - long rate = Math.round(deltaThreadAllocated * multiplier); |
| 54 | + } else if (threadAllocated.compareTo(BigInteger.ZERO) >= 0 && |
| 55 | + lastThreadAllocated.compareTo(BigInteger.ZERO) >= 0 && |
| 56 | + threadAllocated.compareTo(BigInteger.ZERO) >= 0) { |
| 57 | + long rate = Math.round(threadAllocated.subtract(lastThreadAllocated).longValue() * multiplier); |
55 | 58 | callback.accept(rate);
|
56 | 59 | } else {
|
57 | 60 | // Apparently, neither approach did well, just skip this
|
@@ -88,15 +91,16 @@ private static long gcCounts() {
|
88 | 91 | return total;
|
89 | 92 | }
|
90 | 93 |
|
91 |
| - private static long allocatedByAllThreads() { |
| 94 | + /** Total allocation can overflow a long, so using BigInt here. **/ |
| 95 | + private static BigInteger allocatedByAllThreads() { |
92 | 96 | ThreadMXBean bean = (ThreadMXBean)ManagementFactory.getThreadMXBean();
|
93 | 97 | long[] ids = bean.getAllThreadIds();
|
94 | 98 | long[] allocatedBytes = bean.getThreadAllocatedBytes(ids);
|
95 |
| - long result = 0; |
| 99 | + BigInteger result = BigInteger.ZERO; |
96 | 100 | // This is not correct because we will lose allocation data from threads
|
97 | 101 | // that died. Oh well.
|
98 | 102 | for (long abytes : allocatedBytes)
|
99 |
| - result += abytes; |
| 103 | + result = result.add(BigInteger.valueOf(abytes)); |
100 | 104 | return result;
|
101 | 105 | }
|
102 | 106 | }
|
0 commit comments