Class AllocationProbe
The counter is exact rather than sampled: it reports the bytes the thread requested, not what
survived a collection, so a single new inside a measured loop shows up. The work is passed
as a Runnable whose capture happens at the call site, before measuring starts, so building
it costs the measurement nothing.
This used to be six copies, one per package that made such a claim, each saying it was deliberately a copy because the alternative was a shared test module every module would depend on. The test fixtures of the toolkit are that module, in test scope only: nothing that ships depends on it, and a claim that is the same claim in six places is measured the same way in all of them.
-
Method Summary
Modifier and TypeMethodDescriptionstatic booleanstatic longleastAllocatedBy(Runnable work, int attempts) Runsworkonce to load its classes and link its call sites, then measures itattemptsmore times.static long[]typicalAllocatedByEach(Runnable first, Runnable second, int attempts) Measures two variants of the same work alternately, and returns what each of them typically allocated, in order.
-
Method Details
-
isSupported
public static boolean isSupported()- Returns:
- whether this virtual machine counts per-thread allocation; where it does not, an allocation test has nothing to measure and must be skipped rather than passed
-
leastAllocatedBy
Runsworkonce to load its classes and link its call sites, then measures itattemptsmore times.For a claim about one measurement, such as an absolute zero. Two numbers that are going to be compared with each other have to come from
typicalAllocatedByEach(Runnable, Runnable, int)instead, for the reason written there.- Parameters:
work- what to measureattempts- how many times to run it after the warm-up- Returns:
- the smallest measurement, in bytes. The smallest, and not the first or the mean, because the just-in-time compiler occasionally charges a few kilobytes of its own bookkeeping to whichever thread tripped it, which would make a loop that allocates nothing look as though it does; work that genuinely allocates does so on every attempt.
-
typicalAllocatedByEach
Measures two variants of the same work alternately, and returns what each of them typically allocated, in order.Both words are the fix for a failure that looked like flakiness with no cause: two of these numbers subtracted, differing by thirty-two bytes on a whole-suite run, never on a targeted one, and never twice in the same test.
Alternately, because the two numbers are going to be compared. A difference between them only means something if the machine was in the same state for both, and over sixty frames measured one window after the other it is not: the just-in-time compiler changes its mind about the frame path, sometimes part way through a window. One recorded pair had the second window run at 23056 bytes for thirty-eight frames and 23280 for the remaining twenty-two, so its minimum was a state the first window never saw. Interleaved, such a change lands in both within a frame of each other.
Typically, because the counter is an approximation and the minimum is its worst reading.
getThreadAllocatedBytesaccounts at the granularity of the thread's allocation buffer rather than per object, so a single sample can fall below the true per-frame cost and the next makes it up. Taking the smallest of sixty samples therefore selects exactly the most under-reported one, and which window that lands in is chance. The recorded case is unambiguous: sixty frames flat at 3000 bytes in one window, and 3000 in the other for fifty-nine of them with a single frame at 2968 — the widget's describe pass had cost nothing at all, and the thirty-two bytes were the counter's.The median keeps the property the minimum was chosen for, which is that the compiler occasionally charges a few kilobytes of its own bookkeeping to whichever thread tripped it; it simply filters an outlier on both sides instead of one. Nothing is widened: each side is still one exact number and the caller still asserts an exact equality.
- Parameters:
first- one variantsecond- the otherattempts- how many times to run each; the median wants an odd count and takes the lower of the two middle samples when it is given an even one- Returns:
{typical for first, typical for second}, in bytes
-