Skip to content

feat: use jemalloc to fix glibc malloc memory fragmentation - #395

Merged
su-kaka merged 1 commit into
su-kaka:masterfrom
FloatingDream528:feat/jemalloc-memory-optimization
Jul 23, 2026
Merged

feat: use jemalloc to fix glibc malloc memory fragmentation#395
su-kaka merged 1 commit into
su-kaka:masterfrom
FloatingDream528:feat/jemalloc-memory-optimization

Conversation

@FloatingDream528

Copy link
Copy Markdown
Contributor

Summary

  • Problem: Under high-frequency request patterns (20-40 req/min with 141K+ token inputs), glibc's malloc causes severe heap fragmentation. RSS grows to 2.5GB+ while GC-tracked Python objects only use ~1MB. glibc uses brk() for small allocations and never returns freed heap pages to the OS.
  • Solution: Use jemalloc as a drop-in malloc replacement via LD_PRELOAD. jemalloc uses mmap instead of brk, actively returns freed memory to OS. Also adds a periodic gc.collect() + malloc_trim() background task as supplementary cleanup.
  • Result: Memory usage dropped from 2.68GiB → ~460MiB under the same workload.

Changes

Dockerfile

  • Install libjemalloc2 package
  • Set LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 to replace glibc malloc
  • Set MALLOC_CONF="background_thread:true,dirty_decay_ms:5000,muzzy_decay_ms:5000" for aggressive memory reclamation

web.py

  • Add _memory_trim_loop(): periodic (every 60s) gc.collect() + malloc_trim(0) to force return of free heap pages to OS
  • Add memory trim task lifecycle management (start on startup, cancel on shutdown)
  • Fix credential_manager shutdown: use the singleton credential_manager instance directly instead of the always-None global_credential_manager variable

Test plan

  • Deployed to production server and verified jemalloc is loaded (/proc/1/maps shows libjemalloc.so.2)
  • Verified LD_PRELOAD and MALLOC_CONF environment variables are set in PID 1
  • Confirmed memory usage stable at ~460MiB under 20-40 req/min workload (previously 2.68GiB)
  • Verified memory trim task starts on boot and logs reclamation activity
  • No impact on non-Docker deployments (jemalloc/malloc_trim gracefully degrade with try/except)

Problem:
Under high-frequency request patterns (20-40 req/min), glibc's malloc
allocator causes severe heap fragmentation. The process RSS grows to
2.5GB+ while actual Python objects only use ~1MB. glibc uses brk() for
small allocations and never returns freed heap pages to the OS.

Solution:
- Install jemalloc as a drop-in malloc replacement via LD_PRELOAD
- jemalloc uses mmap instead of brk, actively returns freed memory to OS
- Configure aggressive memory reclamation (dirty_decay_ms=5000)
- Add periodic gc.collect() + malloc_trim() loop as supplementary cleanup
- Fix credential_manager shutdown (use singleton instead of unset global)

Result:
Memory usage dropped from 2.68GiB to ~460MiB under the same workload.
@su-kaka
su-kaka merged commit 35c9f5a into su-kaka:master Jul 23, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants