리눅스는 이제 발표 13년차에 들어간다. 1991년 말에 만들어진 리눅스는 초기에는 다른 운영체제에 비해 훨씬 미약한 존재였다. 성능이 우수하지도 않으며 보호 모드에서 간신히 돌아가는 유닉스 클론에 가까웠다. 하지만 개발자들은 리눅스에 열광했다. 그들에게는 자신들만의 유닉스를 PC에서 돌릴 수 있다는 사실만으로도 대단한 일이었다. 이때부터 리눅스 개발자 커뮤니티가 형성되기 시작했다. 이 커뮤니티에 의한 개발 방식은 그 전까지는 유례가 없던 일로, 그 의미와 가치에 대해선 에릭 레이먼드의 「성당과 시장」이라는 글에 잘 요약되어 있다.
리눅스는 초기에 M. Bach가 쓴 책 『The Design of the Unix Operating System』의 구현을 충실하게 따르다가 수많은 시행착오와 개선을 거친 후 일종의 메인스트림 운영체제로 들어섰다. 초기의 리눅스는 기본적으로 AT&T의 ‘System V의 초기 버전 유닉스 커널(System V Release 2, 이하 SRV2)’을 충실하게 따랐다. SVR2 커널은 1980년대 초반에 만들어진 것으로 System V Release 4 이후의 커널과는 많이 다르다. SVR4는 썬 마이크로시스템즈의 구현을 일부 반영하기도 했으며, 많은 부분이 새로 씌어진 보다 본격적인 커널이었다. 아마 SVR4에서 출발했으면 지금과는 다른 모습일 것이라는 게 필자의 추측이다.
이런 해묵은 코드들은 초기의 리눅스 코드들과 비슷하다(관심이 있는 독자들은 http://minnie.tuhs.org/UnixTree에서 역사적인 코드들을 볼 수 있다). 물론 시간이 지나자 코드들은 점점 더 복잡하게 되었으며 이런 코드들뿐만 아니라 코드를 만드는 gcc나 다른 유틸리티들도 함께 복잡해졌다. 리눅스의 초기 코드들은 지금은 소스포지로 옮겨간 Linux Cross refer ence 프로젝트(http://lxr.linux.no)에서 볼 수 있다.
인터넷과 리눅스의 발전
일단 리눅스의 커널이 만들어지자 수많은 GNU 소프트웨어들의 구현이 그 안에서 이뤄졌다(비슷한 시기에 GNU의 애플리케이션이 BSD나 다른 운영체제에서도 구현되었다). 리눅스의 개발이 초창기의 ‘인터넷’을 중심으로 대학에 있는 사람들과 초기의 리눅스 해커들을 중심으로 이루어졌듯이 리눅스의 보급도 버전 1이나 2.0대 초반 버전이 발표되던 시기의 ‘폭발적인 인터넷 보급으로 인한 서버의 필요성’과 맞물렸다.
이 보급이 너무나 빨랐고 초기의 옹호자들이 열성적이었기 때문에 업계가 관심을 가지기 전에 이미 수많은 리눅스 박스들이 서버 하우스 내에서 돌아가고 있었다. 리눅스 업계의 초기 IPO 과정에 인텔을 비롯한 대형 IT 업체들이 관여한 것은 어플라이언스 서버로서의 리눅스의 전략적 가능성을 반영한 결정이었다. 로버트 영이 쓴 『리눅스 혁명과 레드햇』이라는 책은 이러한 상황을 잘 정리했다. 업계들의 리눅스에 대한 관심은 마이크로소프트를 싫어한다기보다는 그 영향권에서 끌려다니기 싫어하는 메이커들의 속사정에도 기인했다.
이와 함께 순수하게 리눅스 자체를 즐기는 개발자들도 늘어났다. 사람들이 여러 가지 이유로 리눅스에 많은 기대를 쏟아붓다보니 리눅스는 하나의 대안이라기보다는 대안의 상징물처럼 보이게 되었다. 업체들은 아무리 많은 돈을 들이더라도 이렇게 완숙한 운영체제를 턱하니 만들 수 없다는 사실을 잘 알고 있었기 때문에 여러 가지 좋은 이유를 대며 리눅스를 옹호하고 지원했다. 메인스트림 운영체제로서의 리눅스는 주장 당시의 초기에는 성능상 논란의 여지가 있었지만 많은 발전이 이루어진 현재는 그렇지도 않다.
얼마 후 리눅스에 대한 이해가 높아지고 플랫폼 이식이 쉬워지자 ARM이나 MIPS, PPC 등을 중심으로 임베디드 리눅스에 대한 관심이 아울러 커졌다. 이것은 리눅스가 발표되고 몇 년이 지나자 자연스럽게 예측되었던 일로 임베디드 리눅스의 수요 역시 꾸준히 증가했다. Lineo의 IPO 이후 많은 임베디드 리눅스 회사가 탄생했다. 국내에서도 마찬가지로 임베디드 리눅스를 표방하는 몇 개의 회사들이 탄생했다.
짧은 기간 동안 많은 변화를 거쳐 리눅스는 커널 버전 2.6대에 이르렀다. 아직은 많은 사용자들이 2.4대의 커널에 머물러 있지만 곧 2.6 커널을 사용할 것이다. 2.4에서도 그렇지만 2.6 커널은 많은 변화를 동반했다. 고성능 서버와 임베디드를 동시에 표방하며 각자가 이루고 싶은 것들을 투영하는 작은 마술상자 같은 리눅스가 버전 2.6에 이른 것이다.
리눅스 2.6 커널에 대해서
리눅스에 관한 책은 아니지만 유닉스의 일종인 솔라리스의 커널 구조를 다룬 『Solaris Internals』의 표지에는 유명한 스포츠카 메이커인 로터스의 엔진 구조도가 나온다(www.solarisinternals.com). 저자들이 커널 책의 제목에 엔진을 표제로 쓴 것은 어쩌면 의미심장하다. 저자들은 커널 아키텍트라기보다는 커널의 튜닝 쪽에 가까운 사람들이다. 커널과 엔진은 유사성이 있어 보인다.
자동차의 엔진이라는 것은 그 자체가 최고의 엔지니어링이면서 엔진의 발전과 변화에 대한 계보가 있고 하나의 엔진 블럭과 헤드가 만들어지면 십여 년간 그대로 사용될 수밖에 없다. 일단 완성된 엔진은 특별한 개선 없이 하나의 존재 그 자체로서 차종의 수명이 다할 때까지 부분적인 최적화를 계속하면서 기술적으로 발전한다. 많은 최신 기술들을 외부에서 들여오기는 하지만 자신의 것으로 만들려면 피나는 노력이 필요하다. 하지만 자동차라는 것은 엔진만으로 만들어지는 것이 아니며 수많은 부품들의 합이다. 조향성이라든가 사용자 인터페이스, 그리고 엔진의 성능과 기타 모든 엔지니어링의 합이다.
유닉스 운영체제도 커널이 매우 중요한 엔진이지만 다른 것들의 도움이 없으면 결코 완성품이 되지 않는다. 또한 엔진들도 점차 복잡해져서 과거의 단순하고 우아했던 엔진 구조의 아름다움은 어디에도 없다. 그럼에도 불구하고 모든 엔진은 같은 목적을 가지고 있으며 구조도 비슷하다. 하지만 여기서 한 가지 확실한 사실이 있다면 엔진을 새로 만들거나 튜닝(개선)하려는 사람이 있다면 엔진의 기본에 대한 흔들리지 않는 지식이 있어야 하고, 실제로 수도 없이 뜯어보고 다른 엔진들과도 비교해 보아야 한다는 것이다. 커널을 엔진에 비유하기는 했지만 완벽한 비유는 아니다.
필자는 어쩌면 일종의 신형 엔진에 비교할 수 있는 리눅스 커널 2.6에 대해 설명하려고 한다. 리눅스 커널 2.6에 이르러 많은 변화가 있었지만 그 중 몇 가지의 중요한 변화에 대해서 간단히 적어보려 한다. 크고작은 변화들이 있겠지만 크게는 쓰레드와 스케쥴러에서 가장 많이 바뀌었다. 문제는 두 주제만 하더라도 단순한 내용이 아니어서 이러저러한 내용이라고 뭉뚱그리고, 관련 서적과 URL로 관심을 돌리는 정도로 끝나고 말 것 같다는 점이다. 쉽게 쓰려고 애를 쓰긴 하겠지만 필자는 독자들이 리눅스 커널 구조에 대해 약간의 관심이 있다고 가정할 수밖에 없음을 양해해 주기 바란다.
쓰레드 구조
쓰레드의 성능과 효율이 프로그램의 전반적 성능에 큰 영향을 끼친다는 것은 당연한 일이다. 시스템 자원과 관련된 쓰레드 사용에 대한 부분은 더욱 그러하다. 필자는 운영체제에서 가장 어려운 부분의 하나가 쓰레드라고 생각한다(리눅스는 쓰레드의 복잡성에서는 예외에 속한다). 쓰레드는 운영체제에서 실행의 단위로 중요한 요소이고 스케쥴러와 긴밀한 관련이 있다. SMP와의 연관성 역시 매우 강하며 쓰레드만으로도 운영체제 교과서를 하나 쓸 수 있을 정도이다.
프로그래밍에서 고전적인 프로세스 모델 대신 쓰레드를 사용하는 가장 중요한 이유는 운영체제의 관점에서 보았을 때 자원 점유 면에서 경제적이기 때문이다. 쓰레드는 1980년대 중반부터 중요한 관심사로 부각되었는데 이 당시부터 솔라리스나 마크(Mach)같은 운영체제는 쓰레드의 개념을 본격적으로 도입하기 시작했다.
과거 마크에서 사용했던 표기 방법을 이용한다면 일반적인 유닉스의 프로세스와 쓰레드 구조는 다음과 같이 요약할 수 있다. 마크의 분류법에 따르면 태스크(task)는 메모리 공간을 비롯한 자원 할당의 기본 단위이며, 쓰레드는 실행의 기본적 단위이다(마크에서는 프로세스를 태스크라는 용어를 사용했기 때문에 쓰레드와 태스크라는 용어를 그대로 사용했다).
◆ 사용자 쓰레드 : 일반적인 태스크 안에 구현되는 사용자 쓰레드는 태스크 내에 사용자 쓰레드를 구현하기 위한 메모리 관리자와 스케쥴러를 따로 설치한다. 쓰레드들을 관리하기 위한 쓰레드 관리자가 필요하다. GNU의 ‘Pthread’나 자바의 ‘쓰레드 관리자’ 같은 구조가 사용자 쓰레드에 속한다.
◆ 커널 쓰레드 또는 경량 쓰레드 : 솔라리스의 LWP(Light Weight Process)나 몇 가지 종류의 커널 쓰레드들이 여기에 해당되는데, 커널은 커널 쓰레드에 대한 CPU의 자원 할당을 관리한다. 커널 쓰레드는 다양한 방식으로 태스크 내에서 사용자 쓰레드와 결합한다.
쓰레드의 구조에 대한 많은 문서들이 있고 서로 상이한 용어를 사용함으로써 많은 혼선이 비롯되었다. 혼란스럽다고 느끼는 독자들에게는 커널 쓰레드 같은 용어를 처음으로 끄집어내고 사용하기 시작한 Tom Doeppner의 문서를 읽어보기를 권한다(http://www.cs. brown.edu/people/twd/는 홈페이지이며 그 중에서 ThreaMon 패키지의 문서의 일부인 http://www.cs.brown.edu/research/thmon/ thmon2a.html은 좋은 요약 문서이다).
결국 쓰레드의 구조는 크게 사용자 쓰레드와 커널 쓰레드가 1:1인 구조, 순수한 사용자 쓰레드의 구현인 1 to Many 구현(1:N), 그리고 솔라리스 등에서 구현되었던 Many to Many(M:N) 구조가 있겠다. 그리고 중간에 매우 혁신적인 Many to Many의 구조를 제시했던 Thomas Anderson의 스케쥴러 액티베이션(Scheduler Actiavtion) 같은 구현이 있다(Anderson, T.E., Bershad, B.N., Lazowska, and Levy, H.M. 1992. Scheduler activations : effective kernel support for the user-level management of parallelism).
독자들이 Anderson의 글을 읽다보면 무언가 영감이 떠오르는 느낌이 들 것이다. 워낙 많은 문서가 있기 때문에 대부분의 운영체제 교과서에서도 이 구조들을 속시원히 알려 주지는 못하고 있다. 필자는 개인적으로 독자들이 U.Vahalia의 「Unix Internals」의 문서들을 읽는 것이 좋은 출발점이라 본다. 본지 자료 중에는 2002년 2월호 ‘운영체제 오디세이’에서 방준영 씨가 쓴 ‘운영체제는 프로그램을 어떻게 실행하는가’라는 글이 좋은 참고가 될 수 있다.
리눅스의 쓰레드 구조와 다른 유닉스 운영체제와의 차이를 비교한다면 리눅스는 전적으로 커널 쓰레드를 통해 쓰레드 구조를 구현하고 있다는 점일 것이다. 리눅스만 커널 쓰레드를 사용하고 있는 것은 아니지만 운영체제마다 차이가 있기 때문에 간단한 설명이 필요하다. 리눅스에서 커널 쓰레드를 지원하는 프로젝트는 몇 가지 대안 중에서 Ulrich Drepper, Ingo Molnar의 NPTL(Native POSIX Thread Library)로 귀결되었다. 이 모델에서는 커널이 각 쓰레드의 생성과 종료 스케쥴링을 관리한다. 이와 반대로 사용자 쓰레드 모델에서는 커널이 프로세스만 관리하고 각 쓰레드들은 사용자 공간에서 관리된다. 순수한 커널 쓰레드/프로세스의 문제라면 너무 거대한 쓰레드, 그러니까 자원 점유량이 많은 쓰레드의 문제가 있고, 순수한 사용자 쓰레드의 문제라면 시스템 콜과의 조율에 문제가 있다.
스케쥴러 액티베이션은 이러한 문제를 업콜(Scheduler Upcall)을 통해 해결하였는데 매우 이상적으로 보였기 때문에 나중에는 솔라리스를 포함한 많은 운영체제가 이 스케쥴러 액티베이션을 구현했다. 스케쥴러 액티베이션은 상대적으로 경량인 IPC와 정교한 쓰레드 구조를 필요로 하는데 구현마다 많은 문제점들이 발생했다. 솔라리스는 기존의 doors 같은 경량의 IPC 구조를 아용하였고 쓰레드 구조는 기존의 M:N 설비를 이용하였는데, 이들은 이미 구현되었던 것들임에도 불구하고 스케쥴러 액티베이션은 구현에 많은 문제점들이 있었다고 전해진다.
Margo Seltzer 등에 의해 이루어진 BSD에서의 초기 구현은 특별히 장점이 없었다. 나중에 NetBSD에서 조금 나은 방법으로 다시 구현되긴 했으나 결정적인 것은 아니었다. 뛰어난 개념이 있지만 빈약한 구현이 언제나 스케쥴러 액티베이션의 문제였다. 결국 1:1 커널 쓰레드의 구현은 크게 나쁜 방법이 아니었다. 리눅스의 단순한 쓰레드 구조와 IPC들을 생각하면 스케쥴러 액티베이션과 비슷한 방법이 크게 유리할 것도 아니기 때문에 자원을 효과적으로 사용할 수만 있으면 현재로서는 1:1이 실용적인 측면에서 더 나을 수도 있다. 이 주제에 대해 더 자세한 내용은 http://people.redhat.com/drepper/ glibcthreads.html에 나온 설명을 참조하기 바란다.
쓰레드의 구현 이외에도 쓰레드의 스케쥴링의 깊은 영역에는 훨씬 더 복잡한 부분이 많지만 리눅스에서는 1:1로 제한해버림에 따라 간단한 프로세서 스케쥴링으로 문제를 단순하게 만들 수 있다. 앞으로 리눅스의 쓰레드와 쓰레드의 스케쥴링이 어떻게 바뀔 지는 모르지만 당분간은 부모 프로세스의 자원을 공유하는 다른 프로세스를 복제하는 현재의 clone() call에서 크게 벗어날 것 같지는 않다. 리눅스 커널의 쓰레드는 프로세스와 다르지 않으나 clone()으로 복제한 프로세스는 부모와 주소 공간, 파일 시스템 자원, 파일 서술자, 시그널 핸들러를 공유할 수 있다. 리눅스의 쓰레드는 비록 프로세스이지만 프로세스의 생성과 소멸 그리고 자원 배치가 무거운(많은 시간과 자원을 소비하는) 편이 아니라는 점을 강조하고 있다(좀 더 자세한 내용은 people.redhat.com/drepper/nptl-design.pdf를 참조).
비록 리눅스가 프로세스와 같은 구현의 간단한 구조의 쓰레드를 사용하고 있지만 비교 또는 이해를 위하여 다른 운영체제의 쓰레드에 관한 문서들도 읽어보기를 강력히 권한다. 그리고 리눅스 쓰레드의 구현 역사와 내부 구조도를 알고 싶은 독자는 『IA-64 리눅스 커널』의 「프로세스, 태스크, 쓰레드」 편을 읽어보면 많은 도움이 될 것이다.
스케쥴러
리눅스의 스케쥴러는 2.2와 2.4 때부터 많은 변화를 겪었기 때문에 혼란스러운 부분도 있다. 2.6 커널의 특징이라고 말하는 O(1) 스케쥴러는 Ingo Molnar에 의해 시험적으로 커널 2.4 때부터 존재했다. 커널의 실시간성이라든가 선점성 같은 부분은 다른 유닉스 운영체제에서도 많은 논란이 있었던 부분이므로 리눅스만의 문제는 아닌 것이다. 매우 방대한 분량의 기본 지식이 필요하긴 하지만 필자는 독자들에게 먼저 U.Vahalia의 『Unix Internal』를 읽어보기를 권한다. 그 다음에 리눅스와 관련된 Robert Love의 『Linux Kernel Development』를 읽기를 권하고 싶다.
얼마 전 에이콘출판사에서 『임베디드 개발자를 위한 리눅스 심층 분석』이라는 제목으로 출판되었다. 리눅스 주요 개발자의 한 사람이 잘 정리된 구성으로 내용을 요약한 책이다. 주로 커널 2.6에 대한 내용을 중심으로 글을 전개했다. 내용이 좋지만 분량이 다소 많은 『리눅스 커널의 이해』를 보고 정리가 안 되는 독자라면 이 책의 잘 요약·정리된 내용을 볼 수 있을 것이다. 사실 권수호 씨의 『리눅스 프로그래밍 바이블』이 나오기 전부터 막연히 웹에 떠도는 문서에서 O(1) 스케쥴러에 대한 글들을 접할 수 있었으나 책으로 알기 쉽게 정리된 것을 보기는 앞의 책에서부터다.
리눅스의 스케쥴러에 관한 중요한 내용을 요약하면 다음과 같다.
◆ 완전한 SMP 확장성을 가질 것. 프로세서 고유의 lock과 실행큐(runqueue) 같은 구조가 필요하다.
◆ SMP와의 상성을 개선한다. 프로세서에 대한 로드밸런서 같은 구조를 구현한다.
◆ 좋은 인터랙티브 성능을 구현한다.
◆ 공평한 스케쥴링이 일어날 수 있도록 프로세스의 타임 슬라이스를 적절히 할당해야 한다.
◆ 많은 수의 SMP에 대해서도 좋은 성능을 낼 수 있도록 확장성을 개선한다.
이러한 목표를 구현하기 위해 스케쥴러는 많은 부분이 변경되어 이전의 커널과는 많이 다르다. 독자들이 궁금해 할 지도 모르는 O(1) 스케쥴러라는 것은 실행큐와 실행큐의 배열에 대한 구조를 변경하면서 구현된다. 기존의 스케쥴러는 이른바 라운드로빈이나 단순한 변형의 형태로 다음과 같이 구현된다.
우선순위를 재계산한다.
타임 슬라이스 값을 재계산한다.
}
이 구현은 간단하지만 문제가 있다. 우선 시스템의 태스크가 많은 경우 일정한 시간 내에 스케쥴링 계산을 완료한다는 보장이 없다. 그리고 우선순위 재계산을 행할 때에는 태스크 디스크립터와 태스크 목록에 대한 보호장치인 락을 걸게 되므로 락의 경쟁 상태가 발생할 수 있다. 새로운 스케쥴러는 이러한 구조가 아니라 각각의 프로세서에 대해 2개의 우선순위 배열을 둔다. 하나는 실행큐에 있는 태스크 중 타임 슬라이스가 남아있는 활성 배열이고 다른 하나는 타임 슬라이스를 다 소진한 비활성 배열이다.
새로운 스케쥴러에서는 타임 슬라리스를 소진한 태스크에 대해 루프에서 우선순위 재계산을 하는 것이 아니라 비활성 배열에 첨가한다. 활성과 비활성 배열은 우선순위 배열로 스케쥴러는 이들에 대한 비트맵 배열을 유지한다. 관심이 있는 독자는 로버트 러브의 책을 읽어보면 그림과 소스가 잘 설명돼 있어 전체적인 구조 파악에 도움이 될 것이다. 그리고 권수호 씨의 책에서 분석한 것은 주로 구조체와 소스코드에 관한 부분이다.
결과적으로 스케쥴러는 비트맵 배열에서 가장 높은 우선순위를 갖는 비트맵을 찾아 해당 태스크를 스케쥴하는 것으로 일정한 시간 내에 모든 태스크에 대한 스케쥴링을 매우 쉽게 처리할 수 있다. 리눅스의 O(1) 스케쥴러는 매우 단순한 아이디어 같지만 좋은 결과를 내고 있다. http://developer.osdl.org/craiger/hackbench/에 성능 평가 그래프가 있다. 또 정말 스케쥴러를 테스트해 보고 싶은 분들은 유영창 씨의 간단한 코드 해킹을 변경하여 몇 가지 테스트를 해볼 수도 있겠다(http://kelp.or.kr/korweblog/stories.php?story=03/12/17/1060745)
선점형 커널
리눅스 2.6 커널의 또 다른 특성이라면 커널 내에서의 선점이 가능하다는 것인데 기존의 커널들은 선점을 허용하지 않음으로써 내부적인 데이터 구조의 자연스러운 보호가 가능한 측면도 있었다. 그러나 스케쥴러의 성능이 향상됨에 따라 선점이 필요해졌고 기존 커널의 선점이 일어나는 경우를 포함해서 선점이 가능한(락이 걸리지 않은) 상태에서는 언제든지 선점 가능하게 되었다.
리눅스 2.6의 중요한 구조 변경 부분은 간단한 쓰레드 구조와 단순하지만 성능이 좋은 O(1) 스케쥴러의 조합으로 이루어진 것이다. 스케쥴러에 대한 글을 쓰고 나니 필자의 실력의 한계가 느껴지는 것 같아 답답하기만 하다. 그래서 요약이 잘 되어 있는 글을 소개하는 게 나을 것이라 생각한다(http://www-903.ibm.com/devel operworks/kr/linux/library/l-inside.html).
메모리 관리
메모리 관리는 크게 두 가지로 나뉜다. 커널 메모리의 관리와 프로세스 어드레스 공간의 관리라는 두 가지의 큰 주제가 있다. 사실 이 부분은 너무 방대한 주제로 지금까지 좋은 책이 없었다고 해도 과언이 아니다(원래 메모리 관리는 필자의 주요 관심사이지만 매우 광범위하므로 이 글에서 다루기는 힘든 주제다. 그래서 간단히 소개만 하겠다). 사람들이 별로 관심을 갖지 않지만 운영체제의 성능에서 병목에 해당하는 부분이기도 하다.
커널 2.6에서의 프로세스 주소 공간의 관리는 Rik van Riel의 r-map(reverse mapping, 역맵핑)이 채용되었고 기존의 Andrea Arcangelli가 개발한 VM(Virtual Memory)의 구조 역시 개선되었다. 현재 리눅스 개발팀은 지금의 VM에 대해서는 과거보다 만족스러운 평가를 내리고 있다. 역맵핑을 통한 성능 개선이 일어났는데, 필자는 본지 2004년 2월호 특집인 64비트 운영체제의 주소 공간 관리에서 이러한 점들을 설명한 적이 있다.
VM에 대해서는 자료가 부족한 편이지만 최근에 좋은 책이 하나 나왔다. 저자는 Mel Gorman으로 책 제목은 『Understanding the Linux Virtual Memory Manager』이다. 이 책은 저자의 홈페이지에서 관리되었던 두 가지 문서(http://www.skynet.ie/~mel/)를 합친 것이다. 이 Mel Gorman의 문서로 많은 사람들이 VM 구조를 접할 수 있었다. 책에는 커널 2.6에 대한 부분이 추가되었다고 한다. 하지만 홈페이지의 문서만으로도 관심 있는 독자들은 많은 도움을 받을 수 있을 것이다.
커널에서도 데이터 스모그 현상!
중요한 이야기는 다 빼놓은 듯하고 책 소개와 URL 적어놓기만으로 끝난 듯한 글을 마무리하면서 필자는 또 한번 가벼운 괴리감에 빠지게 되었다. 조리 있는 설명 능력의 부족이다. 하지만 문헌들은 매우 중요한데, 커널이 본격적인 성능과 구조를 지니게 되면서 참고문헌이나 읽어야 할 책의 분량은 더 많아지고 독자들은 조금씩 더 많은 관심과 실력이 필요하게 되었다. 과거처럼 몇 년 동안 정작 커널의 구조에 관한 책이 단 1~2권 밖에 나오지 않던 시절에 비하면 그래도 낫다고 할 수 있다. 커널 분야에서도 책들이 점차 많아져 이른바 ‘데이터 스모그’ 현상이 오고 있다. @