리눅스 메모리 용어: RSS·PSS·malloc·mmap·fork를 계층별로 구분하기

반응형

시스템 성능을 공부하면 RSS·PSS·malloc·mmap·fork가 한꺼번에 등장한다. 이 용어들은 같은 것을 다른 말로 표현한 것이 아니다. 프로세스의 주소 공간, 현재 RAM에 있는 페이지, C 라이브러리의 할당, 커널의 매핑, 프로세스 생성을 서로 다른 계층에서 설명한다.

용어를 단순히 외우기보다 “무엇을 측정하거나 변경하는가”로 묶으면 메모리 증가를 봤을 때 잘못된 결론을 줄일 수 있다.

RSS·PSS·VSZ는 무엇을 세나

지표 묻는 질문 주의할 해석
RSS 현재 resident한 프로세스 페이지는 얼마인가 공유 페이지가 포함되므로 전부 단독 사용량은 아님
PSS 공유 페이지를 매핑한 프로세스 수로 나눈 비율 합은 얼마인가 정책·시점에 따른 snapshot이지 ‘절대적 실제 사용량’은 아님
VSZ·VmSize 프로세스의 전체 virtual address space 크기는 얼마인가 아직 resident하지 않은 영역과 파일 매핑도 포함할 수 있음

Linux의 /proc/<pid>/statusVmRSS = RssAnon + RssFile + RssShmem으로 표시한다. 다만 커널 문서는 이 값의 일부가 확장성을 위한 계산이라 완전히 정확하지 않을 수 있다고 명시한다. 매핑별 상세 값은 /proc/<pid>/smaps, 프로세스 합계는 smaps_rollup이 더 적합하지만 읽는 비용도 더 크다.

anonymous·file·shmem은 backing의 종류다

  • anonymous memory: 일반 파일에 backing되지 않은 페이지다. heap, stack, anonymous mmap, 언어 runtime 영역 등이 포함될 수 있다.
  • file-backed memory: executable, shared library, memory-mapped file처럼 파일에 backing된 페이지다.
  • shmem: shared memory와 tmpfs 등을 위한 공유 메모리다.

이 구분도 완전히 고정된 상자는 아니다. MAP_PRIVATE로 파일을 매핑한 뒤 page를 수정하면 copy-on-write로 private anonymous page가 생길 수 있다.

또한 시스템 전체의 page cache와 프로세스 RSS를 같은 값으로 보면 안 된다. read()를 통해 커널 page cache에 읽힌 파일 데이터가 모두 해당 프로세스 RSS에 잡히는 것은 아니다. RSS의 RssFile은 프로세스 주소 공간에 매핑되고 resident한 file page를 말한다.

malloc·free와 mmap·munmap은 계층이 다르다

malloc()free()는 C library allocator API다. 현재 프로세스가 확보한 영역을 chunk로 나누고 재사용하는 정책은 allocator 구현이 결정한다. ISO C API는 glibc·jemalloc·tcmalloc의 내부 전략이 같아야 한다고 정하지 않는다.

mmap()munmap()은 virtual address mapping을 만들고 제거하는 Linux system call interface다. glibc allocator는 일부 영역을 확보할 때 전통적인 data segment 확장과 anonymous mmap을 함께 사용할 수 있다. 어떤 경로를 쓰는지는 크기 하나만이 아니라 allocator, 버전, tunable, 기존 arena 상태에 따라 달라진다.

malloc_trim()은 glibc에서 free heap page를 system으로 돌려보내도록 시도하는 GNU 확장이다. 호출하면 RSS가 반드시 줄어든다는 보장은 없고, 재할당 지연과 system call 비용도 함께 재야 한다.

fork와 execve는 새 프로그램을 다루는 방식이 다르다

fork()는 caller와 여러 속성을 공유하거나 복제한 child process를 만든다. Linux에서 memory page는 보통 copy-on-write로 처리되므로 호출 즉시 모든 page 내용을 물리적으로 복사하지는 않는다. 이후 쓰기가 발생하면 해당 page의 private copy가 필요해질 수 있다.

execve()는 새 프로세스를 하나 더 만드는 호출이 아니라 현재 process image를 새 프로그램으로 바꾼다. PID는 유지되지만, signal disposition·memory mapping·open file descriptor 처리는 속성별 규칙이 다르다. 따라서 “메모리를 완전히 초기화하는 재시작”으로만 설명하면 중요한 경계를 놓친다.

지표를 함께 읽는 최소 순서

대상 PID에 대한 읽기 권한이 있는 Linux host에서 다음 값을 같이 본다.

pid=1234

grep -E '^(VmSize|VmRSS|RssAnon|RssFile|RssShmem|VmSwap):' \
  "/proc/$pid/status"

cat "/proc/$pid/smaps_rollup"

status는 빠른 요약, smaps_rollup은 더 상세한 합계다. 두 파일은 서로 다른 시점의 snapshot이며 process map은 계속 바뀐다. 숫자 하나를 정답으로 취급하지 말고 같은 workload 구간에서 추이를 비교한다.

가상 주소와 page table의 관계는 리눅스 가상 메모리의 구조, free() 후 RSS가 유지되는 경우는 free와 RSS를 같이 읽는 법에서 이어서 보면 용어가 실제 증상과 연결된다.

참고 자료

반응형
KEEP READING
카테고리 전체 보기 →

댓글