Compaction and pause budgets: pay for movement deliberately
Relate fragmentation, relocation, pinning, and collection work to a measured latency budget without promising universal pause guarantees.
On this page
The question for today
What you’ll understand
- Explain why total free bytes do not always satisfy a contiguous allocation request.
- Estimate a simplified serial movement budget from measured work rates.
- Separate collection pauses, concurrent CPU overhead, and end-to-end request latency.
A heap can contain plenty of free bytes while lacking a free region suitable for the next allocation. Compaction relocates surviving objects to consolidate space, but movement requires copying and reference maintenance. A useful latency discussion therefore names the work being performed, the threads stopped, and the budget being protected instead of assuming that a collector's label determines every request's delay.
Fragmentation is about the shape of free space
Consider sixteen separated free regions of two MiB each. Their total is 32 MiB, but they do not provide one contiguous eight-MiB region if the allocator cannot combine them or obtain more address space. The actual outcome depends on the runtime's allocation regions, large-object strategy, available mappings, and collection mechanism. This example is a shape argument, not a prediction that every allocator with those free bytes must fail. Internal fragmentation, such as unused bytes inside size-class slots, is a separate accounting category.
A moving collector can pack selected survivors together and make larger free regions available. It must preserve references to the moved objects, including roots and fields that can still be used. Pinning prevents an object from moving for a defined interval, often to support a native operation holding a stable address. Pinned objects can constrain compaction, but their impact depends on placement and the collector's design. Keeping an object alive and keeping its address stable are different obligations; rooting alone does not imply pinning in a moving runtime.
Turn work into a limited timing model
For a simplified stop-the-world phase, separate coordination time, live bytes moved, and reference-update work. Divide each work quantity by an appropriate measured service rate, then add only components assumed to execute serially in the model. A bytes-per-second rate must specify whether it counts logical copied payload or physical read-plus-write traffic. Parallel workers, bandwidth contention, cache effects, and overlapping phases can invalidate a naive sum. Use measurements from comparable heap shapes and load, not a device's advertised maximum bandwidth.
A collector's pause target is not automatically a hard application deadline. Coordination can wait for safe execution points, a workload can change the survivor set, and a concurrent phase can consume CPU while requests continue running. Report global pauses separately from concurrent CPU time and throughput. Do not add unrelated component p99 values and call their sum the end-to-end p99: quantiles do not generally compose that way. Trace actual requests through the relevant intervals and inspect how bursts, queueing, and scheduling amplify or hide a pause.
Tune a lifecycle before buying a bigger heap
First ask whether retained objects are useful. Reducing unnecessary survivors can reduce tracing and movement while improving memory headroom. A larger heap may allow less frequent collection, yet retain more data or produce larger work batches; the tradeoff depends on the collector and application. Reducing pin duration or copying a small native input can sometimes make relocation easier, but an additional copy also has a cost. Compare alternatives under the same request distribution, memory limit, and latency objective, including rare large batches.
The queue lab shows service-rate imbalance rather than actual collector pauses. Press Reset, set arrivals to four and service to two, predict two extra waiting jobs per second, then Play or Step. For a separate experiment, press Reset before setting arrivals to four and service to five; predict the restored four-job initial backlog drains in four seconds, then Play or Step. This can illustrate how reduced effective service capacity accumulates work. The controls do not create periodic stop-the-world intervals, pinned regions, or relocation. In a real service, measure the backlog immediately before and after pauses and the subsequent recovery rate. That evidence connects a collection event to user delay more directly than a heap-size setting alone.
Work it through
Allocate a fictional movement budget
A serial teaching phase has 4 ms of coordination, 6 ms of reference updates, and a measured logical-copy rate of 100 MiB/s. It moves 8 MiB. The desired phase budget is 50 ms.
The movement estimate is 8/100 seconds, or 80 ms. Add 4 ms and 6 ms to obtain a simplified total of 90 ms.
The 50 ms budget leaves 50−4−6=40 ms for movement. At the assumed rate, at most 100 × 0.040 = 4 MiB can be moved within that remaining budget.
Reducing movement to 4 MiB meets the arithmetic model exactly, leaving no uncertainty margin. Measure the actual phase and retain headroom because rates, coordination, and reference work can vary.
The modeled eight-MiB phase exceeds the budget by 40 ms. Four MiB is a model-derived threshold under fixed assumptions, not an operational guarantee.
The living notebook
Explore the model
Interactive lab · queue
Recover service capacity after a slowdown
Press Reset, set λ=4 and μ=2, predict backlog growth of two jobs per second, then Play or Step. For a separate experiment, press Reset, set λ=4 and μ=5, predict the restored four-job backlog drains in four seconds, then Play or Step. This fluid illustration does not simulate stop-the-world pauses, collection phases, fragmentation, or compaction.
- Fluid backlog
- 4
- Net rate · λ − μ
- −1 /s
- M/M/1 mean residence
- 1 s
Fluid backlog starts at 4 and follows max(0, 4 + (λ − μ)t). The separate M/M/1 residence-time formula assumes Poisson arrivals, exponential service and λ < μ. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.
Look forUser delay depends on accumulated work and recovery capacity as well as the duration of an individual pause.
Pause & reason
Check your understanding
Your turn
Try it yourself
Under the worked example's same 10 ms fixed cost and 100 MiB/s logical-copy rate, estimate a phase moving 3 MiB. Name two reasons an observed request can take longer than this phase.
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Convert 3/100 seconds to milliseconds, then include work outside the modeled phase.
Compare with the solution
Movement contributes 30 ms and the modeled phase totals 40 ms. A request may also wait in a queue, perform application computation or I/O, experience scheduling delays, or overlap a different collection event. The simplified phase estimate is neither the entire request duration nor a percentile bound.
Keep the idea
Take it with you
- Free-space shape matters alongside total free bytes.
- Movement budgets require measured rates and explicit serial or parallel assumptions.
- Reachability, address stability, global pauses, and request latency are different properties.
Read further
Original sources and deeper explanations to follow at your own pace.
Optional progress, saved in this browser when available. Revisit any lesson at any time.
Lesson not marked complete.