가능합니다. 오히려 이런 경우는 free의 Used를 구성하는 메모리를 항목별로 분해(Spectrum) 해서 봐야 원인을 찾을 수 있습니다.
질문에서 주신 상황을 정리하면
즉,
RSS(200)
+ Slab(70)
+ Buff/Cache(171)
-------------------
약 441GB
Used = 725GB
=> 약 280GB 정도가 어디 있는지 잘 안보이는 상태
이 정도 차이면 단순 page cache 문제가 아닐 가능성이 있습니다.
Linux에서는 Used 안에 생각보다 많은 항목이 포함됩니다.
Used
├── Anonymous Memory (RSS)
├── File Cache
├── Slab
│ ├── SReclaimable
│ └── SUnreclaim
├── Kernel Stack
├── Page Tables
├── Percpu
├── Vmalloc
├── BPF Maps
├── TCP Buffers
├── UDP Buffers
├── Dentry/Inode Cache
├── XArray
├── Zswap
├── CMA
├── Direct Map
├── Unevictable
├── Mlocked
├── tmpfs
├── cgroup charged pages
├── pinned pages
└── 기타 kernel allocator
개인적으로는 아래 순으로 의심합니다.
① Page Cache (삭제가 안되는 Dirty Page)
Cached
Dirty
Writeback
AIStor는 대용량 sequential IO를 수행합니다.
Dirty Page가 계속 유지되면
free에서는 Used 증가
RSS에는 안보임
이 현상이 발생합니다.
확인
grep -E 'Dirty|Writeback|Cached' /proc/meminfo
② Direct IO가 아닌 일반 buffered IO
DirectPV 자체는 DirectIO를 강제하지 않습니다.
Application이
O_DIRECT
로 열지 않으면
Page Cache
를 많이 사용할 수 있습니다.
③ Kernel Memory (Network)
AIStor + Cilium이면
skb
tcp buffers
xdp
bpf
등이 생각보다 커질 수 있습니다.
특히
sockstat
/proc/net/sockstat
/proc/net/sockstat6
를 봐야 합니다.
④ BPF Map Memory
Cilium은
bpffs
에 map을 유지합니다.
map이 매우 커질 수 있습니다.
확인
bpftool map show
그리고
bpftool map dump
보다는
bpftool map show
에서
bytes_memlock
를 보는 것이 중요합니다.
⑤ Page Tables
엄청난 mmap이 있으면
PageTables
가 수십 GB도 가능합니다.
grep PageTables /proc/meminfo
⑥ Kernel Stack
KernelStack
thread가 수십만개면 커질 수 있습니다.
⑦ Percpu
Percpu
⑧ Vmalloc
VmallocUsed
⑨ Unevictable
Unevictable
⑩ Cgroup memory accounting
질문에서
memory.current = 410GB
라고 하셨는데
RSS = 200GB
라면
memory.current
안에도
cache
slab
kernel memory
가 포함됩니다.
따라서
memory.stat
를 봐야 합니다.
cat memory.stat
가능성은 있습니다.
대표 사례는
cilium bpf ct list
혹은
bpftool map show
에서
cilium_ct4_global
가 매우 커짐.
lb4_services
lb4_backends
lb_affinity
endpoint map
policy map
특히
bpf.masquerade=true
사용 시
BPF map 증가 사례가 종종 보고됩니다.
이 스크립트 하나로
Used Memory Spectrum
처럼 보여주면 원인 파악이 훨씬 쉽습니다.
#!/bin/bash
MEMINFO=/proc/meminfo
get_mem() {
awk -v key="$1" '$1==key":" {print $2}' $MEMINFO
}
TOTAL=$(get_mem MemTotal)
FREE=$(get_mem MemFree)
AVAIL=$(get_mem MemAvailable)
CACHE=$(get_mem Cached)
BUFFERS=$(get_mem Buffers)
SLAB=$(get_mem Slab)
SREC=$(get_mem SReclaimable)
SUNREC=$(get_mem SUnreclaim)
DIRTY=$(get_mem Dirty)
WRITEBACK=$(get_mem Writeback)
SHMEM=$(get_mem Shmem)
PGTABLE=$(get_mem PageTables)
KSTACK=$(get_mem KernelStack)
PERCPU=$(get_mem Percpu)
VMALLOC=$(get_mem VmallocUsed)
UNEVICT=$(get_mem Unevictable)
MLOCK=$(get_mem Mlocked)
ANON=$(get_mem AnonPages)
FILE=$(get_mem FilePages)
echo
echo "========= Memory Spectrum ========="
printf "%-25s %10.1f GB\n" "AnonPages" "$(echo "$ANON/1024/1024" | bc -l)"
printf "%-25s %10.1f GB\n" "File Cache" "$(echo "$CACHE/1024/1024" | bc -l)"
printf "%-25s %10.1f GB\n" "Buffers" "$(echo "$BUFFERS/1024/1024" | bc -l)"
printf "%-25s %10.1f GB\n" "Slab" "$(echo "$SLAB/1024/1024" | bc -l)"
printf "%-25s %10.1f GB\n" " SReclaimable" "$(echo "$SREC/1024/1024" | bc -l)"
printf "%-25s %10.1f GB\n" " SUnreclaim" "$(echo "$SUNREC/1024/1024" | bc -l)"
printf "%-25s %10.1f GB\n" "Dirty" "$(echo "$DIRTY/1024/1024" | bc -l)"
printf "%-25s %10.1f GB\n" "Writeback" "$(echo "$WRITEBACK/1024/1024" | bc -l)"
printf "%-25s %10.1f GB\n" "Shmem" "$(echo "$SHMEM/1024/1024" | bc -l)"
printf "%-25s %10.1f GB\n" "PageTables" "$(echo "$PGTABLE/1024/1024" | bc -l)"
printf "%-25s %10.1f GB\n" "KernelStack" "$(echo "$KSTACK/1024/1024" | bc -l)"
printf "%-25s %10.1f GB\n" "Percpu" "$(echo "$PERCPU/1024/1024" | bc -l)"
printf "%-25s %10.1f GB\n" "Vmalloc" "$(echo "$VMALLOC/1024/1024" | bc -l)"
printf "%-25s %10.1f GB\n" "Unevictable" "$(echo "$UNEVICT/1024/1024" | bc -l)"
printf "%-25s %10.1f GB\n" "Mlocked" "$(echo "$MLOCK/1024/1024" | bc -l)"
echo
echo "========== Totals =========="
printf "%-25s %10.1f GB\n" "Total" "$(echo "$TOTAL/1024/1024" | bc -l)"
printf "%-25s %10.1f GB\n" "Free" "$(echo "$FREE/1024/1024" | bc -l)"
printf "%-25s %10.1f GB\n" "Available" "$(echo "$AVAIL/1024/1024" | bc -l)"
USED=$((TOTAL-FREE))
printf "%-25s %10.1f GB\n" "Used" "$(echo "$USED/1024/1024" | bc -l)"
위 스크립트에 다음 항목들을 함께 수집하면 원인 규명에 큰 도움이 됩니다.
프로세스 RSS/PSS 집계: smem, ps_mem.py 또는 /proc/*/smaps_rollup 기반으로 실제 사용자 메모리 합계.
cgroup v2 메모리 상세: 모든 memory.stat을 순회하여 anon, file, kernel, slab, sock 등을 집계하고 memory.current와 비교.
네트워크 메모리: /proc/net/sockstat, /proc/net/sockstat6에서 TCP/UDP 및 소켓 메모리 사용량 확인.
BPF/Cilium 메모리:
bpftool map show의 bytes_memlock 합계bpftool prog showcilium-dbg bpf map list(사용 가능 시)DirectPV/파일시스템 캐시: Dirty, Writeback, Inactive(file), Active(file)를 시간에 따라 추적.
커널 슬랩 상세: slabtop -o 또는 /proc/slabinfo에서 상위 캐시(dentry, inode_cache, kmalloc-*, skbuff_head_cache, xfs_inode, ext4_inode_cache 등) 확인.
Pinned pages: RDMA, GPU, mlock, get_user_pages() 등으로 고정된 페이지 여부.
Transparent Huge Pages: AnonHugePages, ShmemHugePages, FileHugePages 확인.
현재 제공해주신 수치(RSS≈200GB, Slab≈70GB, Buff/Cache≈171GB, Used≈725GB)를 보면 약 280GB 정도의 공백이 존재합니다. 일반적인 Linux 시스템이라면 이렇게 큰 차이는 흔하지 않으므로, cgroup accounting, BPF/Cilium 메모리, 파일 캐시의 상세 분류(Active/Inactive), 그리고 커널이 추적하는 기타 메모리 항목을 함께 집계하는 것이 가장 중요합니다.
원하시면 이 스크립트를 발전시켜 mem-spectrum.sh 형태로,