skip to content

A large table is released and live data is now tiny, yet the process's resident size has not dropped. Is that a leak?

level: seniorimportance: should knowfreq 38%

answer

  1. freed is not returned
  2. resident size is a high-water mark
  3. large mappings can go back, pooled ones stay
  4. one live object pins a region
  5. the floor of live bytes decides

basics

~20 s

Usually not. Resident size is a high-water mark: a general-purpose allocator keeps freed pages for reuse rather than handing them back, so the process stays near its peak with almost nothing live. A leak shows as live bytes that keep climbing.

solid answer

~50 s

Freeing makes memory reusable **inside the process**; it does not oblige the process to return it to the operating system. Very large allocations served by their own mapping often can be handed back on release, so resident size drops. Allocations served out of an allocator's pooled regions usually are not, because keeping the pages is how the next allocation stays cheap, and a single live object can pin an otherwise empty region. So a flat, high resident size with tiny live data is normally retention, not a leak. The distinguishing signal is the trend in *live* bytes across repeated runs of the same work: a leak has a rising floor of reachable data, while retention has a flat floor under a high, stable ceiling. The practical consequence is that you size the machine for the peak, because the peak is what the process will go on occupying.

go deeper

for a junior

Recall that releasing data and giving memory back to the operating system are two different things. A process can hold a large resident size with almost nothing live in it.

for a middle

Explain the mechanism: an allocator keeps freed pages for reuse, large allocations with their own mapping can go back while pooled ones usually do not, and one live object can pin a nearly empty region.

for a senior

Show the diagnosis: repeat the work in one process and read the floor of live bytes rather than the ceiling. A rising floor is a leak; a flat floor under a high ceiling is retention, and the effort belongs on the peak instead.

for a principal

The angle is what the team's monitoring asserts. If resident size is treated as consumption, every improvement is invisible and every high-water mark looks like an incident - decide which number the alarms and the capacity conversation are actually about.

## Live bytes and resident bytes are different facts Four numbers get called *memory* in this subject, and two of them are in play here: - **live bytes** - what the still-reachable data occupies; - **the process's resident size** - what the operating system currently attributes to the process, which is a high-water mark in practice. When a large table is released, live bytes fall immediately. Resident size need not move at all, and the gap between them is not an error in either measurement. It is the allocator holding space it has not been asked hard enough to give up. ## Why the pages are kept A general-purpose allocator sits between the program and the operating system, and giving pages back is not free: the next allocation would have to ask for them again. So the behaviour splits by how the allocation was served: - **Large allocations given their own mapping.** These can be released to the operating system as a unit when they are freed, and resident size genuinely drops. A single very wide column buffer often falls in this class. - **Allocations served from pooled regions and free lists.** The space is marked reusable and kept. The process's resident size does not move, and it is not supposed to - this is what makes the next allocation of similar size cheap. - **Regions pinned by fragmentation.** A region can be almost entirely free and still unreturnable because one small live object sits in it. Long-running work that interleaves short-lived and long-lived values hits this routinely. A runtime that reclaims unreachable objects adds a second stage to the same story: reclamation makes the bytes free from the program's point of view, and what the allocator beneath does with them is a separate decision. ## Leak or retention? Run the same work several times in one process and watch both numbers: | Pattern | Live bytes across runs | Resident size | Reading | |---|---|---|---| | Retention | flat floor, returns to baseline | high and stable | normal; the peak is being held for reuse | | Leak | floor climbs every run | climbs with it | something reachable is never released | | Fragmentation-heavy | flat floor | creeps upward slowly | reusable space exists but not in the shapes being asked for | | Genuine peak only | flat floor | one jump, then stable | a single large step set the high-water mark | The column that decides it is the **floor of live bytes**, not the ceiling of resident size. A high ceiling with a flat floor is a process that once did something big and is ready to do it again. ## What follows for the work 1. **Size the machine for the peak, not the resting state.** The process will sit at its high-water mark, so the peak is the number that has to fit alongside everything else on the box. 2. **Expect the second big step to be cheaper than the first**, in the sense that it can reuse retained pages instead of asking for new ones. A monitor that alarms on resident size will not show that as an improvement. 3. **Do not chase the number after the fact.** Trying to make a long-running process hand memory back is usually the wrong effort; lowering the peak that created the high-water mark is the effort that pays. 4. **Compare like with like.** A resident figure from a process that has already run one large step is not comparable with one from a fresh process, and the difference is not a regression. ## The reporting failure this causes The most common consequence is not a crash, it is a wrong conclusion. Somebody notices a process holding gigabytes with an empty working set, calls it a leak, and a week of effort goes into memory that was never lost. The check is cheap and it settles the question: does the floor of live bytes come back to where it started after each repetition? If it does, the ceiling is history - a record of the largest thing this process has ever had to hold - and the productive question becomes why the peak was that big, not why the space has not come back.

  • Does releasing one very large column buffer behave differently from releasing many small values?
    Often yes. An allocation big enough to get its own mapping can be handed back to the operating system on release, so resident size falls visibly. Many small values freed from pooled regions leave the pages in the allocator's hands, so resident size does not move even though the same total was released.
  • Two processes do identical work and one reports a much higher resident size. What would you check before calling it a regression?
    Whether they have the same history. A process that has already run one large step sits at that high-water mark and will keep sitting there, while a freshly started one has never allocated it. Compare the floor of live bytes and the peak reached during the step, not the steady resident figure.

A warehouse takes delivery of one enormous shipment and puts up shelving for it. When the shipment leaves, the shelving stays: the floor space is still committed, nothing is on it, and the next big delivery goes up faster because the racking is already there. Asking why the floor space was not given back mistakes readiness for waste.

saying these in an interview costs you the question

  • Calls any high resident size with small live data a leak
  • Believes freed memory must always be returned to the operating system
  • Thinks resident size cannot exceed the bytes currently live
  • Sizes the machine for the resting state rather than the peak
  • Spends effort forcing memory back instead of lowering the peak