Skip to content

Commit cb17df9

Browse files
Rewrite thread alloc calculation to BigInt to avoid overflowing
1 parent b357e10 commit cb17df9

File tree

2 files changed

+13
-9
lines changed

2 files changed

+13
-9
lines changed

build.boot

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
(task-options!
22
pom {:project 'com.clojure-goes-fast/jvm-alloc-rate-meter
3-
:version "0.1.2"
3+
:version "0.1.3-SNAPSHOT"
44
:description "Measure JVM heap allocation rate in real time"
55
:url "http://github.com/clojure-goes-fast/jvm-alloc-rate-meter"
66
:scm {:url "http://github.com/clojure-goes-fast/jvm-alloc-rate-meter"}

src/jvm_alloc_rate_meter/MeterThread.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package jvm_alloc_rate_meter;
22

33
import com.sun.management.ThreadMXBean;
4+
import java.math.BigInteger;
45
import java.util.function.LongConsumer;
56
import java.lang.management.GarbageCollectorMXBean;
67
import java.lang.management.ManagementFactory;
@@ -34,24 +35,26 @@ public MeterThread(LongConsumer callback, int intervalMs) {
3435
// one if it did.
3536

3637
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);
3840
try {
3941
while (doRun) {
4042
long heapUsage = usedHeap();
4143
long gcCounts = gcCounts();
42-
long threadAllocated = allocatedByAllThreads();
44+
BigInteger threadAllocated = allocatedByAllThreads();
4345
long time = System.currentTimeMillis();
4446

4547
double multiplier = 1000.0 / (time - lastTime);
4648
long deltaUsage = heapUsage - lastHeapUsage;
47-
long deltaThreadAllocated = threadAllocated - lastThreadAllocated;
4849

4950
if (lastTime != 0) {
5051
if ((gcCounts == lastGcCounts) && (deltaUsage >= 0)) {
5152
long rate = Math.round(deltaUsage * multiplier);
5253
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);
5558
callback.accept(rate);
5659
} else {
5760
// Apparently, neither approach did well, just skip this
@@ -88,15 +91,16 @@ private static long gcCounts() {
8891
return total;
8992
}
9093

91-
private static long allocatedByAllThreads() {
94+
/** Total allocation can overflow a long, so using BigInt here. **/
95+
private static BigInteger allocatedByAllThreads() {
9296
ThreadMXBean bean = (ThreadMXBean)ManagementFactory.getThreadMXBean();
9397
long[] ids = bean.getAllThreadIds();
9498
long[] allocatedBytes = bean.getThreadAllocatedBytes(ids);
95-
long result = 0;
99+
BigInteger result = BigInteger.ZERO;
96100
// This is not correct because we will lose allocation data from threads
97101
// that died. Oh well.
98102
for (long abytes : allocatedBytes)
99-
result += abytes;
103+
result = result.add(BigInteger.valueOf(abytes));
100104
return result;
101105
}
102106
}

0 commit comments

Comments
 (0)