글 수 367
리눅스 메모리 관리, 왜 메모리 여유공간이 없을까?
Revision 2.3
Copyright 2004 sapphirecat. 이 글은 Creative Commons License을 따릅니다.
(원문 : Linux Memory Management or 'Why is there no free RAM?')
Sections
1. 메모리 관리 소개
2. x86 상의 알 수 없는 880MB 제한
3. VIRT, RES, 및 SHR사이의 차이
4. 버퍼와 캐시의 차이
5. 스왑 (2.6 커널)
1. 메모리 관리 소개
top과 같은 일반적인 Unix 도구들은 시스템이 잠시 구동된 후 여유 공간이 얼마되지 않는다고 종종 보고합니다.
(예를 들어, 약 3시간 가량 시스템을 가동하면)
현재 제가 이 글을 작성하고 있는 이 머신은 512MB 크기의 RAM임에도 불구하고 단지 60MB 이하의 메모리 여유 공간이 있다고 보고합니다. 모두 어디로 간 것일까요?
이렇게 보고되는 메모리가 사용되는 가장 큰 공간은 디스크 캐시(Cache)에 있습니다. (필자의 경우 현재 약 290MB 이상 입니다.)
이러한 캐시 영역은 top에 의해 "cached"라고 표시됩니다.
캐시 메모리는 실행 중이거나 새로 시작될 프로그램이 메모리를 필요로 한다면 빠르게 대체되어야 하기 때문에 OS에서는 항상 여유있는 만큼 확보하게 됩니다.
UNIX가 디스크 캐시용으로 메모리를 이렇듯 많이 사용하는 이유는...
캐시가 사용되지 않으면 RAM이 모두 낭비되기 때문입니다.
캐시를 유지한다는 것은 어떤 프로그램이 같은 데이터를 다시 필요로 하고 있다는 것으로, 캐시에서 정보를 읽어 들이는 것은 하드 디스크에서 읽어 들이는 것에 비해 약 1000배 이상 빠릅니다.
캐시에서 정보를 가져올 수 없다면, 하드 디스크에서 읽어 들여야 하기에 그만큼 많은 시간이 소요됩니다. (그러나 정보의 손실은 없습니다.)
응용 프로그램을 사용하기 위해 얼마 정도의 여유 메모리가 있는지를 확인하기 위해서는 다음 명령어를 실행하세요.
# free -m
-m 옵션은 메가바이트를 의미하며 결과값은 아래와 같습니다:
total used free shared buffers cached
Mem: 503 451 52 0 14 293
-/+ buffers/cache: 143 360
Swap: 1027 0 1027
-/+ buffers/cache 라인에는 메모리의 사용량 및 다른 응용 프로그램을 사용하기 위한 여유 공간이 얼마나 되는지를 보여줍니다.
일반적으로 작은 스왑이 사용되면, 메모리 사용량은 성능에 어떠한 영향을 주지 않습니다.
제 시스템에는 512MB의 메모리가 있음에도 단지 503MB만이 사용 가능하다고 나와있습니다.
이것은 커널이 스왑을 할 수 없어서, 커널이 차지하는 메모리 공간은 절대로 사용될 수 없기 때문입니다.
시스템의 아키텍쳐에 따라서, 다른 목적을 위해서도 하드웨어에 의해 혹은 하드웨어를 위한 메모리가 점유되어 있는 공간이 있을수도 있습니다.
2. x86 상의 알 수 없는 880MB 제한
기본적으로, 리눅스 커널은 적은 메모리만으로도 실행할 수 있으며 관리가 가능합니다.
그래서 페이지 테이블 관리가 조금은 용이하게 되고, 순서대로 메모리로의 접근이 조금 더 빨라지게 됩니다.
단점은 일단 RAM의 총 용량이 880MB에 근접해지면 커널은 모든 메모리를 사용할 수 없게 됩니다.
이것은 지금까지 문제가 되지는 않았지만 데스트톱의 경우 그러한 상황이 발생될 수 있습니다.
1GB 이상의 RAM을 모두 사용하려면, 커널은 재컴파일되어야 합니다.
'make menuconfig' (또는, 사용하는 어떤 config 파일도 가능)을 열어 다음의 옵션을 설정하세요.
Processor Type and Features ---->
High Memory Support ---->
(X) 4GB
이것은 2.4 및 2.6 커널에 적용됩니다.
높은 메모리를 지원한다는 것은 이론적으로 메모리 접근 속도가 다소 느려지게 되는 것이지만, Joseph_sys와 log에 따라서 실제적으로는 차이가 없습니다.
3. top의 출력에서 VIRT, RES, 그리고 SHR의 차이점
VIRT는 하나의 프로세스의 가상 크기 (virtual size of a process)를 의미하는데, 그 프로세스가 실제로 사용하고 있는 메모리의 총량으로, 프로세스에 대응되는 메모리 (예, X 서버의 비디오 카드 RAM), 프로세스에 대응되는 디스크상의 파일들 (대부분 주로 공유 라이브러리들), 그리고 다른 프로세스와 함께 공유되는 메모리입니다. VIRT는 현재 시점에서 어떤 하나의 프로그램이 접근 가능한 메모리의 크기가 얼마나 되는지를 보여줍니다.
RES는 현재 점유하고 있는 메모리 크기 (resident size)를 의미하는데, 하나의 프로세스가 실제 물리 메모리를 얼만큼 소비하고 있는가는 보여주는 것입니다. ( 이것은 또한 %MEM 열에 직접적으로 대응합니다.) 대부분의 프로그램들이 C 라이브러리에 의존하기 때문에 RES는 항상 VIRT 크기보다 작습니다.
SHR은 얼마 정도의 VIRT 크기 만큼 공유될 수 있는가를 보여줍니다. (메모리 또는 라이브러리) 라이브러리의 경우에는 모든 라이브러리가 메모리에 들어 있다는 것이 아닙니다. 예를 들어, 한 프로그램이 어떤 라이브러리의 아주 적은 함수만을 사용한다면, 모든 라이브러리는 대응이 되고 VIRT와 SHR에서 라이브러리 수가 측정되지만 단지 사용되고 있는 함수가 포함된 해당 라이브러리 파일의 일부분만 실행되고 RES에 의해 측정될 것입니다.
4. 버퍼와 캐시의 차이
버퍼는 특정 블록 장치와 관련이 있으며 파일시스템의 메타데이터를 캐시에 저장하는것 뿐만 아니라 in-flight 페이지를 추적하는 것 또한 할 수 있습니다. 그러나 캐시는 캐시에 저장된 파일 데이터만을 유지합니다.
즉, 버퍼가 디렉터리에는 무엇이 있는지, 파일들의 권한들은 어떠한가를 저장하며, 어떤 메모리가 특정 블록 장치를 위해 기록이 되거나 혹은 읽어 들여지는 가를 추적합니다. 그러나 캐시는 파일들의 내용 그 자체만을 유지할 뿐입니다.
이 부분에 대해 더 정확히 아시는 분은, 정정 및 부연 설명을 해주시기 바랍니다.
저는 /proc/meminfo가 이러한 결론에 도달하기 위해서 어떻게 처리되는가를 알아보는 것에 근거하여 다소 추측을 포함해 작업하였기 때문입니다.
5. Swappiness (커널 2.6)
2.6 버전 이후로, 메모리가 꽉 차게 될 때, 리눅스는 캐시의 크기를 축소하는 것과는 달리, 얼마의 메모리를 디스크로 스왑해야 하는지를 조율하기 위한 방법이 있었습니다.
어떤 하나의 응용 프로그램이 메모리를 필요로 하나 모든 RAM이 사용되고 있을 때, 커널은 일부 메모리 공간을 확보할 수 있는 두 가지 방법을 가지고 있습니다.
커널은 가장 오래된 데이터를 삭제함으로써 RAM에 있는 디스크 캐시를 줄인다거나, 상대적으로 덜 사용되는 부분 (페이지)를 디스크의 스왑 파티션 밖으로 스왑할 수도 있습니다.
그러나 이 두가지 방법 중 어떤 것이 더 효과적인가는 미리 알 수 없습니다.
커널은 최근의 활동 기록을 바탕으로 주어진 시간에 두 가지 방법 중 효과적인 것을 추측하여 결정을 하게 됩니다.
커널 2.6 이전 버전에서는 사용자가 그러한 계산에 영향을 미칠 수 있는 수단이 없었으며 커널이 종종 잘못된 결정을 하게 되어 성능이 저하되고 느려지게 되는 상황이 발생하기도 했습니다. 2.6 버전에 swappiness가 추가됨으로써 이러한 문제를 해결하였습니다.
Swapiness는 응용 프로그램을 스왑하고 캐시를 비워두는 것 사이에 균형의 변화를 주기 위해서 0에서 100까지 중 하나의 값을 선택합니다. 100을 선택하면, 커널은 사용하고 있지 않은 페이지들을 찾아내어 모두 스왑해 버립니다. 다른 경우에는, 스왑이 응용 프로그램이 메모리를 얼마나 점유하고 있는지 그리고 얼마나 적은 캐시가 사용하지 않는 것들을 찾아내고 빼내는가에 따라 스왑이 발생할 수도 있고 그렇지 않을 수도 있습니다.
기본적으로 swappiness의 값은 60입니다. 0은 메모리가 필요했던 응용 프로그램들이 캐시의 크기를 줄여서 RAM의 아주 작은 부분만 할당되게 할 수 있는 이전의 방식에 가깝게 되게 합니다. 랩톱의 경우 주로 디스트 회전 속도가 감소하기 때문에 20의 swappiness 값을 권장합니다.
sysctl으로, swapiness는 런타임시 다음과 같은 명령어들을 통해 설정될 수 있습니다.
# sysctl -w vm.swappiness=30
# echo 30 >/proc/sys/vm/swappiness
예: Gentoo boot가 etc/sysctl.conf에서 설정될 때 기본값
# Control how much the kernel should favor swapping out applications (0-100)
vm.swappiness = 30
예: Asianux Server 3의 기본값
# sysctl -a | grep vm.swappiness
vm.swappiness = 60
일부 패치셋에서는 커널이 자동적으로 swapiness 레벨을 지정할 수 있게 하여 사용자 설정 값을 유지하지 않을 수도 있습니다.