Skip to content

feat(ai-file): trim glibc on a period, and on every environment

변재혁 requested to merge feature/DOP-AI_memtrim-주기화 into develop

The threshold policy from 1a8c0443 never fired and was never going to. It gated on anon/limit >= 0.60 = 614MB, but pptx peaked at 464MB (45.3%) and xlsx at 229MB (22.4%). No extension reached it, so MEMTRIM logged nothing - which reads as "no memory problem" rather than "never measured". That is the most dangerous way for this switch to fail.

The 0.60 came from calibrating against a 233MB floor that was itself wrong: that was the floor of a pod that had already taken load. The clean cold floor right after redeploy is 167.6MB.

Rather than re-guess the ratio, drop it as the policy. The cost it was defending against is not worth defending: the only price of a trim is re-faulting what was handed back, 8095MB is roughly 20k pages = 2040ms, against a pptx job of 1.79~3.48s. At a 60s period that is under 0.1%.

So the gate opens (0.01, below the 16% cold floor) and the cooldown becomes the sole governor - one trim at the first job boundary after 60s. Time, not job count, so the frequency is the same whatever the extension or the limit.

Three things this buys beyond firing at all:

  • The ratio cannot be calibrated in the first place. The floor differs per extension (pptx 233MB, xlsx ~199MB, clean 167.6MB) and we have not measured docx/html/hwp yet, so there is no value to pick.
  • The floor does not scale with the limit, so the same ratio means different absolute headroom per environment. A ratio policy cannot be uniform across dev/stg/prod even when the number is identical.
  • Trimming every period makes post-trim anon the pod's floor, and the trend of that floor is the verdict: flat with a large reclaimed_mb is glibc fragmentation, rising is real retention. That is the measurement we need for the remaining extensions, and the gate was suppressing it.

And fix the scope bug: memtrim was declared only in config_dev.yml, so stg and prod fell through to the model default (false) and had it off entirely. dev/stg/prod now declare the same three values, the model default is on, and a test asserts the three ymls stay identical - if they drift, dev's measurement stops describing production.

The gate stays as an escape hatch (AI_FILE_MEMTRIM_THRESHOLD_RATIO). Raising it past the cold floor makes it the governor again and brings back the silence, so the startup log now says which of the two is in control, and a test pins 0.01 < 167.6/1024 so the policy cannot flip quietly.

Note what this does not do: the threshold was never a wall, only a trigger. malloc_trim returns physical pages of already-freed chunks, so it bounds fragmentation and nothing else. If an extension turns out to hold memory for real, reclaimed_mb will be ~0 and the pod still climbs to the limit.

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com

Merge request reports