가상 메모리에 대한 내용은 다른 토픽들을 이해하는데 중요한 바탕이 될 뿐 아니라 다양한 문제를 해결하기 위해서도 필요한 내용입니다. 하지만 가상 메모리에 대해 잘 정리된 문서들을 찾아보기도 힘들뿐더러 그 내용도 매우 어렵습니다. 미천한 제 지식이라도 도움이 되었으면 해서 용기를 내어 이 토픽을 다루어 볼까 합니다.
가상 메모리 vs. 물리 메모리
독자들이나 필자나 개발을 하다 보면 별별 문제와 씨름을 하게 된다. 이런 문제들 중 하나가 바로 메모리 부족 오류, 즉 Out Of Memory 오류이다. 대개 OOM이라 부르는데, 오죽 많이 당했으면 줄여서 부르기까지 하겠나 하는 생각이 든다. 암튼 OOM이 떨어지면 언넘이 시스템의 메모리를 다 쳐먹는지 궁금하기 마련이다. 대개 사용되는 도구들은 작업 관리자나 성능 모니터 혹은 Windows Vista부터 새로이 제공되는 리소스 모니터 등이다. 그런데…… 요 쉬키들이 알려주는 메모리 사용량은 대략 난감한 용어들로 범벅이 되어 있다. 그냥 퉁 쳐서 메모리 사용량 몇 KB 라고 알려주면 좀 좋겠냐 마는 작업 집합이니 커밋이니 당췌 뭔 말인지도 모르겠는데 이것들이 다시 공유니 개인이니 하면서 또 나눠진다. 게다가 이 도구가 보여주는 메모리 사용량과 다른 모니터링 도구가 보여주는 메모리 사용량의 값 조차 다르다!
그런 도구들이 그렇게 이런 저런 용어를 써 가면서 메모리 사용량을 다르게 표시하는 데에는 다 이유가 있다. 메모리가 어떻게 사용되는가를 바라보는 관점에 따라서 메모리 사용량이란 값이 달라지기 때문이며 OOM을 해결하는 데에는 다양한 관점에서 메모리 사용량을 파악해야 하기 때문이다. 결론은 “퉁 쳐서 메모리 사용량 얼마”라는 것은 문제를 해결하는데 아무런 도움도 안 된다는 말이 되겠다.
그래서…… 그런 용어들이 도대체 무슨 의미를 갖는지 설명이 필요한 것이다. 그런데 그런 용어를 이해하려면 가상 메모리에 대한 기본적인 이해를 요구한다. 뭐 필자가 포스트 하나 날로 쳐 먹으려면 관련 자료 링크 하나 툭 던져주고 필자가 하고 싶은 말만 해도 될 것이다. 하지만 쓸데 없이 정의감에 불탄 필자, 미친 척하고 가상 메모리라는 것부터 시작하고자 한다.
아마도 여러 포스트를 통해서 물리 메모리, 가상 메모리, 주소 공간(address space), 페이징, 예약된 메모리, 커밋 된 메모리, 작업 집합 등을 살펴보게 될 것이다. 필자가 오늘, 그리고 앞으로 다룰 토픽들은 모두 응용 프로그램 개발자로서 알아야 할 수준 정도만을 언급할 것이다. 운영체제나 디바이스 드라이버를 작성하는 개발자 수준이라면 훨씬 더 깊은 지식이 필요하겠지만 그 정도까지 일반 개발자들이 알 필요는 없다고 생각한다. 어디서 운영체제 코드 좀 만지고 왔다고 여기 와서 이건 틀리네 저것이 맞네 라고 필자에게 시비 걸지 말기 바란다. 이 글의 목적은 일반 어플리케이션 개발자가 러프하게 개념을 잡을 수 있도록 쓴 글이다. 필자도 십 수년 전에는 한 운영체제 했던 사람이다(라고 쓰고 책임 회피라고 읽는다).
물리 메모리(Physical Memory)
물리 메모리의 개념은 매우 쉽다. 여러 분의 데스크톱 컴퓨터 혹은 노트북을 열어서 눈으로 볼 수 있고 만질 수 있는 것이 바로 물리 메모리이다. 물리 메모리는 하드웨어이기 때문에 컴퓨터에 설치된 만큼만 사용이 가능하다. 서버들은 4GB ~ 32GB 정도의 메모리를 가지고 있고 PC들은 적게는 1GB(요즘은 많지 않은 듯)의 메모리를 가지고 있고 많게는 8GB를 보유한 PC도 흔히 찾아 볼 수 있다.
과거의 시스템들은 이 물리 메모리 만을 사용하여 운영체제와 어플리케이션을 모두 구동하였다. 만약 시스템에 설치된 메모리가 64KB 였다면 이 물리 메모리 내에서 운영체제, 어플리케이션, 데이터들이 모두 공존하였다는 말이다. 64KB 메모리를 가진 컴퓨터가 있었냐고? 필자가 처음 프로그래밍을 시작한 컴퓨터가 64KB의 메모리를 가지고 있었다!
점차로 컴퓨터가 많이 활용됨에 따라서 운영체제는 여러 어플리케이션을 동시에 구동해야 했으며 이들 어플리케이션은 물리 메모리를 나누어 써야 했다. 그리고 물리 메모리는 금방 동이나 버리기 일쑤였다. 그래서 값비싼 물리 메모리(응? 비싼가?)를 최대한으로 활용할 방법들이 연구되었고, 그 중 하나가 가상 메모리 기법이다. 과거에는 다양한 방법의 가상 메모리 기법이 있었지만 최근에는 인텔이 서버 및 PC 용 CPU에 아도를 치면서 인텔 기반의 컴퓨터에서는 거의 페이징 기반의 가상 메모리 기법이 사용된다고 보면 된다(리눅스가 아닌 UNIX류에서 어케 가상 메모리를 구현하는지 필자도 모른다. 구글신 거거싱~).
가상 메모리(Virtual Memory)
가상 메모리는 말 그대로 가상의 메모리이다. 한정된 물리 메모리만을 사용하지 않고 디스크와 같이 느리지 않고(!) 값싼(SSD는 비싸드라…) 저장 장치를 활용하여 어플리케이션들이 사용할 수 있는 메모리가 많이 존재하는 것처럼 구라를 쳐주는 것이 바로 가상 메모리 이다.
프로세스(어플리케이션)이 메모리를 요청하면 운영체제는 사용 가능한 물리 메모리를 가상 메모리로써 할당해 준다. 프로세스들이 메모리를 사용함에 따라서 점차로 물리 메모리가 소진될 것이고 언젠가는 물리 메모리가 부족하게 될 것이다. 이 때부터 가상 메모리의 진가가 발휘된다. 프로세스가 요청한 만큼의 메모리를 물리 메모리에서 할당 할 수 없게 되면(실제로는 가용한 물리 메모리가 일정 수준 이하로 떨어지면) 운영체제는 미래에 액세스 가능성이 낮을 것으로 기대되는 물리 메모리를 저장 장치(backing storage 혹은 backing store)에 백업하고 그 물리 메모리를 프로세스에게 할당해 준다. 이렇게 물리 메모리를 빼앗기게 되는 프로세스를 희생양(victim)이라 부르고 물리 메모리의 내용을 저장 장치에 기록하는 것을 스왑 아웃(swap-out)이라 부른다.
그림1은 프로세스 B가 메모리 할당을 요청해 왔으나 물리 메모리가 부족한 상황을 보여주고 있다. 이 경우 운영체제는 희생양(이 경우 프로세스 A)을 찾아 적당한 물리 메모리를 저장 장치에 기록하고 이제 사용 가능하게 바뀐 메모리를 프로세스 B에게 할당해 준다.
그림1. 물리 메모리 부족 시 저장 공간을 사용하여 가상 메모리 확보 (만지면 커져요)
희생양이 된 프로세스가 나중에 빼앗겼던 메모리를 다시 액세스 하게 되며 어떻게 될까? 운영체제는 사용 가능한 물리 메모리를 다시 희생양에게 할당하고 저장 장치에 백업 해 두었던 내용을 할당한 물리 메모리에 적재해 준다(스왑 인; swap-in 이 되겠다). 희생양이 되었던 프로세스는 자신이 메모리를 빼앗겼다는 것을 전혀 인지하지 못하게 된다. 물론, 희생양에게 돌려줄 물리 메모리가 부족하다면 운영체제는 다른 희생양을 찾게 된다. 희생양을 찾는 알고리즘은 운영체제 이론에서 많이 다루어지며 수많은 관련된 논문이 있지만 대개 MRU(Most Recent Used) 알고리즘(최근에 액세스된 메모리는 다시 사용될 가능성이 높으므로 가장 최근에 사용되지 않은 메모리가 희생양이 됨)이 사용되곤 한다.
그림2. 저장 장치에 존재하는 메모리 액세스로 인한 스왑 인 발생 (만지면 커져요)
가상 메모리는 CPU와 같은 하드웨어와 운영체제의 합작품이다. 예를 들어, 그림2에서 프로세스 B가 저장 장치로 스왑 아웃 된 메모리를 액세스 하는 것을 어떻게 알아낼 수 있을까? 그것은 CPU의 MMU(Memory Management Unit)가 존재하지 않는 물리 메모리를 프로세스 B가 액세스 한다는 것을 알아채고 운영체제에게 이를 고자질 해주기 때문이다. 운영체제는 사용 가능한 물리 메모리를 할당하고 저장 장치에서 프로세스 B가 사용했던 메모리 내용을 읽어 들이며 다시 MMU를 제어하여 프로세스 B가 동일하게 메모리를 액세스 하도록 해준다. 사실 말이 간단하지 이 과정을 상세하게 이야기 하자면 책 한 권 분량의 내용이 거뜬히 나온다. 필자가 서두에서 언급했듯이 상세한 내용은 죄다 패스(응?) 했다.
이런 방식으로 운영체제는 가상 메모리를 통해 프로세스에게 시스템에 설치된 물리 메모리 보다 훨씬 더 많은 메모리가 존재하는 것과 같은 환상을 심어 줄 수 있는 것이다. 실제로 프로세스 B는 자신이 존재하지 않는 물리 메모리를 액세스한다는 것도 인지하지 못하며 운영체제가 저장 장치에서 자신이 사용했던 메모리의 내용을 불러온다는 것도 인지하지 못한다. (왼손은 거들뿐)
간단한 실험
요기까지만 글을 쓰고 말면 말 그대로 말 잔치로만 끝나는 “이론”으로 끝난다. 필자는 이론가지고 노는 걸 그닥 좋아하지 않는다. 이 글에서 설명한 내용을 실전(?)에 적용해 보자. Windows XP를 아직도 사용하고 있는 독자들에게 미안하지만 여기서 설명할 내용은 Windows Vista 이상에서만 적용될 것이다. Windows XP는 써 본지도 오래되었고 이제 저물어 가는 운영체제이므로 시간을 뺏기고 싶지 않다. 대충 비슷한 도구를 구동시키고 비슷한 내용으로 때려 맞춰주기 바란다(쏘뤼~~).
먼저 가장 손쉽게 접근할 수 있는 Windows 작업 관리자를 구동하고 성능 탭을 살펴보자. 마이크로소프트의 멋진(!) 번역 센스에 욕지거리를 한번 해준 다음 그래프 하단 왼쪽의 “실제 메모리” 항목을 살펴본다. 작업 관리자는 물리 메모리 사용 현황에 대해 간략한 상황을 보여준다.
(이건 만져 봤자 크기가 같아요)
- 전체(Total): Windows에서 사용가능 한 전체 물리 메모리의 양. 32비트 윈도우라면 최대 3GB를 넘을 수 없다. 이는 시스템의 그래픽 카드와 같은 다양한 하드웨어들을 위해 예약된 주소 공간(다음 글에 설명할 것임) 때문이다.
- 캐시됨(Cached): 물리 메모리를 놀려 두는 건 비싼 시스템 자원에 대한 직무유기이다. 따라서 Windows 운영체제는 사용하지 않는 물리 메모리를 파일 캐시와 같이 적극적으로 다른 용도로 사용한다. 물론, 이 메모리는 프로세스가 메모리 할당을 요청하면 언제든지 프로세스에게 할당 할 수 있도록 되어 있다.
- 사용가능(Available): 프로세스가 메모리를 요청하면 Windows는 먼저 ‘여유’ 메모리를 이용하고 여유 메모리가 부족하면 파일 캐시로 사용했던 메모리를 사용하게 된다. 따라서 사용 가능 메모리는 캐시됨 + 여유의 값이다.
- 여유(Free): 운영체제/프로세스에 의해 사용되지도 않고 파일 캐시로도 사용되지 않는, 말 그대로 순수하게 사용 가능한 물리 메모리의 양이다.
- 응? 사용중인 메모리 양은? 그래프에 있자나!
사용 가능 메모리의 양을 살펴보면 약간 의아해 할 것이다. 실제로 “캐시됨” 메모리의 양과 “여유” 메모리의 양을 합쳐도 “사용가능” 메모리 보다 부족하기 때문이다. (1749MB + 337MB = 2086MB > 2030MB)
이 의문점은 작업 관리자 하단의 “리소스 모니터” 버튼을 클릭해 보면 해결이 가능하다. 리소스 모니터를 구동하고 메모리 탭을 살펴보면 멋진 “실제 메모리” 그래프가 나온다. 여기서 다시 한번, 그리고 아까보다 더 시게 마이크로소프트의 번역을 욕해 주자.
(이것도 만지나 마나 같은 크기예요)
- 하드웨어 예약(Hardware reserved): 앞서 언급했듯이 하드웨어 인터페이스를 위한 예약된 주소 공간에 의해 사용할 수 없는 물리 메모리의 양이다. 32비트 운영체제에서 3GB 이상의 메모리를 사용한다면 이 항목을 볼 수 있을 것이다.
- 사용중(In Use): 프로세스나 운영체제에 의해 사용 중인 물리 메모리의 양이다.
- 수정한 날짜(Modified): 어떻게 Modified라는 단어를 이렇게 번역을 했는지 신기할 따름이다. 어찌되었건 이 값의 의미는 Windows의 파일 캐시 메모리 중에서 그 내용이 수정되었지만 아직 파일에 기록되지 않은 메모리의 양이다. 이 메모리를 프로세스에게 할당하려면 먼저 이 메모리의 내용을 파일에 기록해야 한다. 따라서 “수정된 날짜” 메모리(허허)는 곧바로 사용가능 한 물리 메모리가 아니다. 언젠가(곧) 이 메모리의 내용은 파일에 기록될 것이며 파일 기록 후에는 “캐시됨” 메모리에 포함되게 될 것이다.
- 대기모드(Standby): 작업 관리자의 “캐시됨”과 같은 의미이다. 물리 메모리 할당 요청에 따라 언제든지 사용할 수 있다는 의미에서 스탠바이(standby)라는 이름이 사용된 듯 하다.
- 캐시됨(Cached): “수정한 날짜” 메모리(쩝…)와 대기모드 메모리의 합으로써 캐시에 사용된 전체 물리 메모리의 합이다. (1693MB + 56MB = 1749MB)
- 여유(Free): 작업 관리자의 “여유”와 같은 의미이다.
작업 관리자에서 말하는 여유 메모리는 “캐시됨” 메모리와 “여유” 메모리의 합에서 곧바로 사용할 수 없는 “수정된 날짜” 메모리(아놔!)를 뺀 값이 되겠다. (2030MB = 1749MB + 337MB – 56MB)
작업 관리자와 리소스 모니터 외에도 성능 모니터(perfmon.exe)를 통해서도 물리 메모리의 사용 현황을 살펴볼 수 있지만 그 내용을 여기서 다루지 않을 것이다. 지금도 내용이 너무 많은데다가 성능 모니터에서 제공하는 물리 메모리 사용 현황은 훨씬 더 복잡하기 때문이다.
마치며……
이번 포스트는 이 정도로 마치고자 한다. 원래는 간단히 물리 메모리와 가상 메모리의 차이점 정도만을 언급하려 했는데 길어져 버렸다. 다음 포스트에서는 가상 메모리에 대한 보다 상세한 내용으로써 주소 공간의 의미가 무엇인지 살펴보고 간략하게나마 페이징에 대해 살펴보도록 하겠다. 이 글에서 개략적으로 언급한 내용이 다음 포스트에서 Windows 운영체제 상에서 구체적으로 무엇을 의미하는지 설명하게 될 것이다. 다음 포스트가 언제 게시될지는 필자도 모른다. 내용이 간단하지 않고 복잡하고 많은 내용을 간략히 쉽게 설명해야 하기 때문이다. 뭐 관심 있는 독자들도 없겠지만……
경고 : 이 글을 무단으로 복제/스크랩하여 타 게시판, 블로그에 게시하는 것은 허용하지 않습니다.