문서가 닫힐 때 malloc_trim으로 빈 메모리를 OS에 돌려준다
glibc는 free한 메모리를 바로 OS에 돌려주지 않는다. 큰 객체(문서·방)가 닫힐 때 간격을 두고 malloc_trim(0)을 부르면 RSS 355MB가 229MB로 줄었다.
pycrdt 문서처럼 큰 객체를 오래 들고 있다가 닫는 파이썬 서버에서, 객체는 다 풀렸는데 RSS가 내려가지 않는다. 운영 프로세스를 들여다보니 힙 318MB 가운데 206MB가 빈 채로 남아 있었다.
원인은 glibc 할당자다. glibc는 free한 메모리를 바로 OS에 돌려주지 않고 다음 할당을 위해 들고 있는다. 파이썬 객체 기준으로는 누수가 아닌데, OS가 보기에는 메모리를 계속 쥔 것처럼 보인다.
큰 객체가 닫히는 시점에 malloc_trim(0)을 불러 빈 힙을 돌려준다. 이렇게 하자 RSS가 355MB에서 229MB로 내려갔다. 너무 자주 부르면 그 자체가 비용이니 최소 간격(예: 1분)을 둔다. 여러 문서가 한꺼번에 닫혀도 1분에 한 번만 부른다.
import ctypes
import ctypes.util
import time
_libc = ctypes.util.find_library("c")
_trim = getattr(ctypes.CDLL(_libc), "malloc_trim", None) if _libc else None
_last = 0.0
def trim_memory(min_interval: float = 60.0) -> None:
global _last
now = time.monotonic()
if _trim is None or now - _last < min_interval:
return
_last = now
_trim(0)
malloc_trim은 glibc에만 있다. musl(alpine), macOS, 윈도에는 없으니 위처럼 없으면 조용히 건너뛰게 둔다.