출처 : http://blog.nextcube.pe.kr/entry/mkswap-%EA%B3%BC-swapon-swapoff-%EB%AA%85%EB%A0%B9%EC%96%B4
1. swap ?
swap 이란 하드디스크를 메모리처럼 사용하는 기법
물리적인 메모리가 모자라면 하드디스크를 메모리처럼 데이터를 기록하여 메모리를 확보
프로그램들을 많이 실행해서 메모리가 부족해지면, 메모리 상에 적재된 프로그램 중 지금 당장 필요하지 않은 프로그램 데이터를 하드디스크에 옮겨서 메모리 공간을 확보
2. mkswap
swap 파티션이나 swap 파일을 생성하는 명령어
사용
옵션
예문
10240K 사이즈의 /swap_file 생성
dd 명령으로 swap 파일로 사용할 파일을 용량이 넉넉한 파티션에 생성 후
mkswap 명령으로 해당 파일을 swap 파티션으로 만들어준다.
3. swapon
swap 파티션이나 swap 파일을 구동하는 명령어
사용
옵션
-s : swap 파티션의 상태를 보여줌
예문
/etc/fstab 에 있는 swap 을 모두 활성화
4. swapoff
swap 파티션이나 swap 파일의 구동을 중단시키는 명령어
사용
예문
Chapter 5. 메모리 관리
- 여기서는 리눅스 메모리 관리에 대하여 설명한다. 즉, 가상 메모리와 디스크 버퍼 캐쉬와 같은 내용에 대해 다룬다. 그리고 메모리 관리가 필요한 이유와 그에 필요한 작업들, 그밖에 시스템 관리자로서 관심을 가져야 할 여러 주제들을 설명할 것이다.
가상 메모리란?
리눅스는 가상 메모리(virtual memory)란 것을 지원한다. 이것은 메모리 사용량이 늘어남에 따라, 디스크의 일부를 마치 확장된 RAM처럼 사용할 수 있게 해주는 기술이다. 이 기술에 따르면, 커널은 실제 메모리(RAM)에 올라와 있는 메모리 블록들 중에 당장 쓰이지 않는 것을 디스크에 저장하는데, 이를 통해 사용가능한 메모리 영역을 훨씬 늘릴 수 있게 된다. 만일 디스크에 저장되었던 메모리 블록이 다시 필요하게 되면 그것은 다시 실제 메모리 안으로 올려지며, 대신 다른 블록이 디스크로 내려가게 된다. 그러나 이런 과정이 일어나고 있다는 것이 사용자에게는 전혀 보이지 않으며, 프로그램들에게도 그저 많은 양의 메모리가 있는 것처럼 보일 뿐이어서, 점유하고 있는 메모리가 디스크에 있는지 실제 메모리에 있는지 전혀 신경쓸 필요가 없게 된다. 그러나, 하드디스크를 읽고 쓰는 시간은 RAM보다 훨씬 느리기 때문에(보통 천배쯤 느리다), 프로그램의 실행은 그만큼 더디게 된다. 이렇듯 가상적인 메모리로 쓰이는 하드디스크의 영역을 `스왑 영역(swap space)'이라고 한다(swap은 바꿔치기를 한다는 뜻).
리눅스는 스왑 영역으로 일반적인 파일을 사용할 수도 있고 별도의 스왑을 위한 파티션을 사용할 수도 있다. 스왑 파티션은 속도가 빠른 반면에, 스왑 파일은 그 크기를 자유롭게 조절할 수 있다(또한 스왑 파일을 사용하면, 리눅스 설치시에 파티션을 다시 해야 할 필요없이 모든 것을 그냥 설치할 수 있다). 스왑 영역이 얼마나 많이 필요한지를 미리 알고 있다면 그만큼 스왑 파티션을 잡으면 된다. 그러나 스왑 영역이 얼마나 필요할지 확실히 모른다면, 우선 스왑 파일을 사용해서 시스템을 가동해 보고 필요한 공간이 얼마인지 파악한 후에 스왑 파티션을 잡도록 하자.
또한 리눅스에서는 여러개의 스왑 파티션과 스왑 파일을 섞어서 사용할 수 있다. 이 방법을 이용하면, 언제나 큰 용량의 스왑 영역을 잡을 필요없이 그때 그때 필요한 만큼만 스왑을 늘려줄 수 있으므로 편리하다.
운영체제 용어에 관한 이야기 : 컴퓨터 과학에서는 스와핑(해당 프로세스 전체를 스왑 영역으로 내보냄)과 페이징(몇 킬로바이트의 작은 단위로 내보냄)을 구별하는 것이 일반적이다. 이 중에서 페이징이 좀더 효율적인 방법이며, 리눅스에서도 이 방법을 쓴다. 그러나 전통적인 리눅스 용어로는 이 두가지를 모두 뭉뚱그려서 스와핑이라고 흔히 불러왔다.
스왑 공간 생성하기
스왑 파일은 평범한 파일이다. 즉, 커널이 보기엔 일반 파일과 다를 바가 없다. 다만 다른 점이라면 스왑 파일에는 빈틈(holes)이 없으며, mkswap과 함께 사용하게 되어 있다는 점 정도이다. 그리고 스왑 파일은 꼭 자신의 파일시스템(local filesystem)에 있어야 하며, NFS를 통해 마운트된 파일시스템에 있어선 안 된다.
스왑 파일 안에 홀(hole)이 없어야 한다는 점은 중요하다. 스왑 파일은 디스크의 일부를 미리 점유하고 있는데, 이렇게 하면 디스크 섹터를 일일이 할당하는 과정을 거치지 않고서도 메모리 페이지를 파일로 빠르게 스왑시킬 수 있다. 즉, 커널은 파일에 미리 할당되어 있는 섹터를 곧바로 사용하기만 하면 되는 것이다. 스왑 파일 안에 빈틈이 있다는 것은 아무 섹터도 할당되지 않은 공간이 파일 안에 있다는 뜻인데, 이렇게 되면 커널이 스왑을 사용하는데 곤란을 겪게 된다.
홀이 없는 스왑 파일을 생성하기 위한 좋은 방법은 다음과 같다.
$ dd if=/dev/zero of=/extra-swap bs=1024 count=1024 1024+0 records in 1024+0 records out $ |
스왑 파티션도 사실 특별한 것은 없다. 만드는 것도 다른 보통 파티션과 다를 것이 없지만, 특별한 점이라면 스왑파티션에는 어떤 파일시스템도 사용되지 않으며 날것(raw partition) 그대로 쓴다는 점이다. 스왑용으로 쓸 파티션은 type 82로 지정해 두는 것이 좋은데, 이렇게 해두면 파티션의 용도가 명확해진다. 그러나 사실 커널은 이런 것에 그다지 구애받진 않는다.
스왑 파일이나 스왑 파티션을 만들고 나면, 그 앞부분에 일종의 인식표를 달아두어야 한다. 여기에는 커널이 사용하는 몇가지 정보가 위치하게 된다. 이것을 해주는 명령어는mkswap인데, 다음과 같이 쓰인다.
$ mkswap /extra-swap 1024 Setting up swapspace, size = 1044480 bytes $ |
mkswap 명령은 사용에 주의가 필요하다. 이 명령은 파일이나 파티션이 사용 중인지 아닌지를 판별해 주지 않기 때문이다. 따라서 mkswap을 부주의하게 사용하면 중요한 파일과 파티션을 간단히 날려버릴 수 있다! 그러나 다행히도, mkswap 명령은 주로 시스템 설치시에만 사용된다는 점이 우리를 안심시켜 주긴 한다.
리눅스의 메모리 관리자는 각각의 스왑 공간의 크기를 약 127MB로 제한하고 있다(몇가지 기술적인 이유로 인해 실제 한계치는 (4096-10) * 8 * 4096 = 133890048 bytes 즉 127.6875 megabytes이다). 대신, 최대 8개의 스왑 공간을 연결해 사용하면 스왑을 대략 1GB까지 확장할 수가 있다. [1]
스왑 공간 사용하기
스왑 공간을 초기화하는 데는 swapon 명령을 사용한다. 이 명령은 커널에게 해당 공간을 스왑으로 사용할 수 있다는 점을 알려준다. 이 명령에게는 추가하고자 하는 스왑 공간의 경로를 인수로 전달해 주어야 한다. 임시 스왑 파일을 스왑 공간에 추가하고자 한다면 다음과 같이 한다.
$ swapon /extra-swap $ |
/dev/hda8 none swap sw 0 0
/swapfile none swap sw 0 0 |
free 명령을 쓰면 스왑의 사용 상황을 모니터 할 수 있다. 이것은 현재 얼마나 많은 용량의 스왑이 사용되고 있는지 알려준다.
$ free total used free shared buffers Mem: 15152 14896 256 12404 2528 -/+ buffers: 12368 2784 Swap: 32452 6684 25768 $ |
마지막 줄인 Swap:은 위와 같은 항목을 스왑 공간에 똑같이 적용시킨 내용이다. 이 항목이 모두 제로라면, 스왑 공간이 아예 동작하고 있지 않다는 뜻이다.
같은 정보를 top 명령이나 /proc/meminfo 파일을 통해 얻을 수 있다. 그러나 어느 경우든, 특정한 스왑 공간에 대한 정보를 얻는 것은 좀 어렵다.
스왑 공간은 swapoff 명령으로 기능을 멎게 할 수 있다. 그러나 임시로 잡은 스왑 공간이 아니라면, 스왑을 끌 필요는 없다. 만약 스왑을 끄게되면, 스왑 공간에 들어있던 메모리 페이지들이 먼저 실제 메모리로 들어가야 되는데, 실제 메모리에 여유가 없는 경우에는 또 다른 스왑 공간으로 방출되게 된다. 그런데 이 메모리 페이지들을 모두 수용하기에 가상메모리마저도 부족하다면, 그때부터는 리눅스 시스템이 무진장 버벅대기 시작할 것이다. 시간이 아주 많이 걸린 후에는 좀 잠잠해지겠지만, 여전히 시스템은 사용불능 상태에 있게 된다. 따라서 스왑을 끄기 전에, 충분한 여유 메모리가 있는지 꼭 확인해 보아야만 한다(free 같은 것으로).
swapon -a 명령으로 자동적으로 사용되는 스왑 공간들은, 마찬가지로 swapoff -a 명령을 써서 끌 수 있다. 이것도 역시 /etc/fstab 파일에 나열되어 있는 스왑 공간만을 끄기 때문에, 나머지 수동으로 추가시킨 스왑들은 영향을 받지 않는다.
때때로, 실제 메모리가 많이 비어 있는데도 불구하고 스왑을 아주 많이 쓰고 있는 경우를 보게 될 수가 있다. 보통 이런 일이 발생하는 경우는 이렇다. 어떤 덩치 큰 프로세스가 실제 메모리를 많이 점유하는 바람에 시스템이 스왑을 많이 사용하게 되었다고 하자. 이 프로세스가 종료되면 실제 메모리엔 여유 공간이 많이 남게 되지만, 스왑으로 한번 내려간 데이터는 그것이 당장 필요하지 않는 한 실제 메모리로 불려지지 않는다. 따라서 스왑 영역을 많이 사용하면서도 실제 메모리가 많이 비어있는 현상이 꽤 오래 지속될 수 있는 것이다. 그러므로 이런 현상에 특별히 신경쓸 필요는 없다. 하지만, 최소한 그 원리는 이해하고 있어야 나중에 불안하지 않을 것이다.
다른 운영체제와 스왑 공간을 공유하기
가상 메모리 기술은 이미 많은 운영체제에 내장되어 있다. 그런데, 운영체제는 단지 그것이 실행 중일 때만 스왑을 필요로 한다. 따라서 한 컴퓨터에서 다양한 운영체제를 사용한다면, 각각의 운영체제마다 따로 스왑 공간을 마련해 주는 것은 낭비일 것이다. 실제로 서로 다른 운영체제가 스왑 공간을 공유하는 것이 가능한데, 다만 그렇게 하기 위해서는 조금의 해킹이 필요하다. 실제로 이것을 어떻게 구현할 수 있는가에 대한 정보는 각종 Tip이나 HOWTO를 참고하기 바란다.
스왑 공간 할당하기
보통, 스왑 공간을 잡을 때는 그 크기를 물리적인 메모리의 두 배 정도로 하는 것이 적당하다고 말하는 사람들이 많은데, 사실 이것은 좀 근거없는 이야기이다. 여기서 좀더 합리적인 방법을 알아보도록 하자.
우선, 필요한 메모리의 총량을 어림잡아 본다. 필요한 메모리의 총량이라는 것은, 한순간에 필요한 메모리의 최대 크기, 즉 한꺼번에 돌리고 싶은 모든 프로그램들이 필요로 하는 메모리의 총량을 말하는 것이다. 실제로 원하는 모든 프로그램을 한번에 다 띄워놓는다면 바로 이런 상태를 만들 수 있다.
예를 들어, X를 띄우고 싶다면 여기엔 대략 8MB 정도의 메모리 할당이 필요하다. gcc를 돌리고 싶다면 보통 4MB 정도가 필요하지만, 특별히 큰 프로그램을 컴파일한다면 아마 수십 메가바이트 이상이 필요할 것이다. 또한 커널은 그 자체가 대략 1MB 정도 차지하며, 일반적인 쉘들과 작은 유틸리티들은 각각 수백 킬로바이트 정도 잡아먹는다(다 합치면 1 메가 정도 될 것이다). 이런 어림짐작들이 꼭 정확해야 할 필요는 없지만, 좀 더 비관적인 태도로 계산해 볼 필요는 있다.
한가지 명심할 것은, 만약 같은 프로그램을 동시에 돌리고 있는 여러 사람이 있다면, 이들도 모두 각각 메모리를 잡아먹는다는 점이다. 다만, 예를 들어, 같은 프로그램을 두사람이 돌린다고 했을 때 그 메모리 점유량이 원래의 꼭 두배가 되는 것은 아닌데, 왜냐면 프로그램의 실행 코드와 공유 라이브러리들은 메모리에 한벌씩만 올려두고 공유해 사용할 수 있기 때문이다.
free와 ps 명령을 적절히 사용하면 메모리 필요량을 알아보는 데 유용하다.
이제, 앞에서 나온 값에다 안전보장용 여유분을 좀 더하자. 이렇게 하는 이유로서는, 우선 프로그램의 크기 계산이 틀렸을 수도 있고, 또한 실행하고자 하는 프로그램을 몇개 빠뜨렸을 수도 있기 때문이다. 이런 경우를 대비하여 좀 여유 공간을 두어야 하는데, 필요하다고 계산된 크기의 10% 정도를 여유로 잡아두면 충분할 것이다.(스왑을 너무 적게 잡는 것보다는 너무 많이 잡는 것이 낫지만, 그래도 지나치게 많은 양을 스왑으로 잡는 것은 낭비일 뿐이다. 스왑이 더 필요하다면 나중에 추가할 수도 있다.) 이렇게 필요한 크기가 계산되었으면, 편의를 위해 반올림을 해서 메가바이트 단위로 만들자.
위의 계산에 근거하면, 총 얼마 정도의 메모리가 필요한지 파악이 될 것이다. 이제, 필요한 스왑 공간을 계산하기 위하여, 총 필요 메모리량에서 실제 물리적 메모리량을 빼자.(어떤 UNIX 버전에서는, 실제 물리적 메모리의 이미지를 위한 공간까지 스왑에 포함시켜주어야 한다. 이런 경우에는 위의 두번째 단계에서 산출된 필요 메모리 크기 전부를 스왑 공간으로 할당해야 하며, 빼기를 해서는 안된다.)
만일 산출된 스왑 공간이 실제 메모리의 두배를 넘는다먼, 실제 메모리를 좀 더 확충하는 방안을 고려해 보자. 그러지 않는다면 시스템이 아주 기어가게 될 것이다.
계산 결과 스왑 공간이 전혀 필요없다고 해도, 약간의 스왑을 잡아두는 것이 좋다. 리눅스는 메모리에 될 수 있는 대로 많은 여유공간을 확보하려 하는데, 이를 위해 스왑을 아주 적극적으로 사용한다. 즉, 실제 메모리에 여유가 많이 있다 하더라도, 사용되지 않고 있는 메모리 페이지가 있다면 그 부분은 스왑 영역으로 내려진다. 이처럼 디스크가 쉬고 있을 때 미리 스왑을 해두기 때문에, 스왑으로 인한 지연 시간을 많이 줄일 수 있다.
또한 스왑 공간은 여러개의 디스크에 나누어져 있을 수도 있는데, 이렇게 하면, 디스크의 속도와 그 액세스 방식에 따라서 스왑 성능이 향상되기도 한다. 그 밖에도 여러 방식이 있을 수 있으므로 그것을 시험해 보고 싶겠지만, 보통 그런 방식들은 제대로 시험해 보기가 쉽지 않다. 특히, `어떤 방식이 다른 것보다 훨씬 월등하다'는 식의 말은 절대로 믿지 마라. 그런 것들은 거의 언제나 사실이 아니다.
버퍼 캐쉬
디스크를 읽는 일은 (진짜) 메모리를 읽는 것보다 아주 느리다. [1] 더구나, 디스크의 동일한 영역을 짧은 시간 동안 반복해서 계속 읽는 일은 아주 빈번하다. 예를 들어, 누군가 e-mail 메시지를 읽고, 답장을 하기 위해 편집기로 불러들이고, 그걸 보내기 위해 메일프로그램에게 다시 읽게 하는 과정을 생각해 보자. 또한 ls 명령어 같은 것을 시스템의 모든 사용자들이 얼마나 자주 사용할지 생각해 보자. 따라서, 디스크로부터 한번 읽어들인 정보를 메모리에 상당시간 보관한다면, 첫번째로 읽을 때만 시간이 좀 걸릴 뿐 속도가 전반적으로 빨라질 것이다. 바로 이런 것을 가리켜 디스크 버퍼링(disk buffering)이라고 하며, 이런 목적으로 쓰이는 메모리를 버퍼 캐쉬(buffer cache)라고 부른다.
그러나 메모리는 아쉽게도 한정된, 아니, 아주 귀중한 자원이기 때문에, 버퍼 캐쉬는 보통 큰 크기를 가질 수 없다(즉, 우리에게 필요한 모든 데이터를 담아둘 수 있을 정도로 크지는 않다). 따라서, 캐쉬가 다 차게 되면 오랫동안 쓰이지 않은 데이터는 버려지며 그 빈 공간을 새로운 데이터가 메우게 된다.
이런 디스크 버퍼링은 쓰기에도 똑같이 적용된다. 보통, 데이터들은 쓰여지자 마자 또 곧바로 다시 읽어들여지므로(예를 들어, 소스 코드 파일은 일단 파일로 저장된 후, 컴파일러에 의해 다시 읽어들여진다), 이런 데이터들을 캐쉬에 넣어둔다면 확실히 효율적일 것이다. 또한, 쓰기 작업을 디스크에 즉시 하지 않고 캐쉬에 넣어두면, 프로그램들이 그만큼 출력을 빨리 끝낼 수 있기 때문에 전반적인 시스템 성능향상에도 도움이 된다.
대부분의 운영체제들이 버퍼 캐쉬를 갖고 있긴 하지만(좀 다른 이름으로 불릴 수도 있다), 모두가 위와 같은 원리로 동작하는 것은 아니다. 한가지 방법은 write-through라는 것인데, 이 방법은 쓰기를 할 때면 언제나 디스크에도 즉시 기록하는 것이다(물론 캐쉬에도 남겨둔다). 또 다른 방법은 write-back이라 불리는 것으로, 쓰기를 일단 캐쉬에 해 두었다가 나중에 한꺼번에 디스크에 기록하는 방식이다. 효율적이기는 write-back 방식이 뛰어나지만, 대신 약간의 에러가 발생할 소지가 있다. 즉, 시스템이 갑자기 멈춰버린다거나, 전원이 갑자기 나가버린다면, 또는 캐쉬 내용을 미처 써 넣기 전에 플로피를 빼 버린다면, 캐쉬에 담겨 있던 내용들은 고스란히 날아가 버리고 만다. 특히, 손실된 정보가 파일시스템 유지에 필요한 중요 데이터였다면, 자칫 전체 파일시스템을 망가뜨리고 마는 결과를 초래할 수도 있다.
이렇기 때문에, 컴퓨터를 끄기 전엔 반드시 적절한 셧다운 절차를 밟아야만 하는 것이고(Chapter 6 참조), 마운트한 플로피를 빼기 전엔 꼭 언마운트를 해야하는 것이다. 한편, 캐쉬를 디스크로 내보내기(flush) 위한 명령으로 sync가 있는데, 이 명령을 쓰면 아직 기록되지 않고 캐쉬에 남아있는 데이터들을 모두 디스크에 써넣게 되므로, 모든 내용이 안전하게 기록되었다는 점을 보장받을 수가 있다. 또한 전통적인 UNIX에는 update란 백그라운드 프로그램이 있어서, sync가 해주는 것과 같은 일을 30초에 한번씩 자동으로 해준다. 그러므로 사실 sync를 별로 사용할 필요는 없는 없는 셈이다. 특히, 리눅스에는 추가적인 데몬으로 bdflush란 것이 있는데, 이 것은 sync에 비해선 상당히 불충분하게flush 작업을 하지만 대신 좀더 자주 실행하도록 되어 있다. 이런 방식이 고안된 이유는, sync가 디스크 입출력을 순간적으로 과도하게 일으키면서 시스템이 멈춰버리는 현상이 종종 있어 왔기 때문이다.
리눅스에서는, update에 의해 bdflush가 구동된다. 보통 때는 이 데몬들에 별로 신경 쓸 필요가 없지만, 만일 bdflush가 어떤 이유로 죽어버린다면 커널이 이 사실을 바로 알려줄 것이다. 이럴 때는 수동으로 실행시켜 주면 된다(/sbin/update).
그런데, 사실 캐쉬는 파일을 버퍼링하는 것은 아니고, 실제로는 디스크 입출력의 가장 작은 단위인 블록을 버퍼링한다(리눅스에서는 보통 1KB 크기이다). 그렇기 때문에, 디렉토리라든가, 수퍼 블록들, 다른 파일시스템의 유지 데이터, 심지어 파일시스템이 없는 디스크까지도 캐쉬될 수가 있는 것이다.
캐쉬의 효율성은 기본적으로 그 크기에 좌우된다. 캐쉬의 크기가 너무 작으면, 다른 데이터를 캐쉬하기 위해서 캐쉬된 데이터를 계속 내보내야 하므로, 사실상 작은 캐쉬는 별 쓸모가 없는 셈이다. 캐쉬가 어느 정도 쓸모있기 위한 최소한의 크기는, 얼마나 많은 데이터가 읽고 씌여지는지와, 같은 데이터가 얼마나 자주 액세스되는지에 달려있는데, 이것을 알아보기 위한 단 하나의 방법은 그저 실험해보는 것 뿐이다.
만일 캐쉬의 크기가 고정되어 있다면, 그 크기가 너무 큰 것도 곤란한 일일 것이다. 캐쉬가 너무 크면 여유 메모리는 그만큼 줄어들 것이고, 많은 스와핑을 일으켜서 시스템은 느려지게 된다. 리눅스는 자동적으로 모든 RAM의 빈공간을 버퍼 캐쉬로 사용하여 메모리의 효율성을 높이려 하는데, 프로그램들이 많은 메모리를 필요로 할 때는 자동적으로 캐쉬를 크기를 줄여 준다.
그래서, 리눅스에서는 캐쉬를 사용하는 데 대해서 아무것도 신경쓸 필요가 없다. 완벽하게 자동적이기 때문이다. 다만, 셧다운 할 때와 플로피를 빼낼 때의 절차는 꼭 지켜 주어야 한다. 이것만 빼면, 걱정할 것은 하나도 없다.
Notes
[1] | RAM 디스크의 경우는 제외이다. 이것은 RAM에 만들어진 가상의 디스크이므로, 당연히 램만큼이나 속도가 빠르다. |
'개발자 기본 소양' 카테고리의 다른 글
diff 로 두 디렉토리 파일 비교 (0) | 2012.05.23 |
---|---|
디스크와 파일 시스템 (0) | 2012.05.08 |
오픈소스 라이센스 비교 (0) | 2012.04.11 |
VIM을 사용하자 (0) | 2011.03.16 |
메크로 포함한 gcc옵션 -E (0) | 2011.01.11 |