Software Development

More Exceptional C++

More Exceptional C++

Herb sutter“Exceptioanl C++”의 후속작이다. Exceptioanl C++ 처럼 Guru of the Week item을 책으로 엮어서 펴낸 책이다. 때문에 책에 있는 내용들은 거의 전부 웹에서 볼 수 있고 내용도 거의 비슷하다.

C++ In-Depth 시리즈의 번역 quality는 그동안 믿을만 했기 때문에, 별 걱정 없이 번역판을 읽었다. 이로써, 그 시리즈의 번역된 중급서들은 다 읽은 셈이다.

내용은 Scott Meyers의 Effective C++과 비슷한 부류의 것을 기대하면 된다. 즉, C++ 언어를 잘 쓰는 것에 대한 책이다. 여러가지 주제를 다루고 있어서 딱히 한정해서 얘기하기는 힘들 것 같다. 목차를 살펴보라.

형식은 C++ programming 시에 발생하는 문제들을 내놓고 이에 대한 답을 제시하는 식이다. (혹자는 문제집 풀고 있냐고…) 개인적으로 문답법을 상당히 좋아하긴 하지만, 이 책을 읽을 때는 그냥 무시하고 죽죽 읽어나가버렸다.

지금 읽는 소프트웨어 개발 관련 책만도 2권이나 있고 다른 읽을 책도 많지만, C++ 언어 계열로 더 읽는다면, 최근에 C++ In-Depth 시리즈에 추가된 Herb Sutter와 Andrei Alexandrecu의 저작, C++ Coding Standards를 꼽고 싶다. 제목으로부터 오해할 가능성이 높겠지만, tab size를 어떻게 쓰고, bracket 위치를 어디에 두는가에 관한 책이 아니다. 실제로 읽기 전엔 모르겠지만, EC++ 계열의 practice들을 정리해서 “표준적인 coding style”로 집약한 책으로 보인다. 하나를 더 고르라면, C++의 아버지 Bjarne Stroustroup이 C++ 언어의 진화 과정을 설명하고 왜 현재의 문법이 생겼는지를 설명해주는 Design & Evolution of C++을 꼽겠다. 언어의 역사를 이해하는 것은 언어의 철학을 이해하는 데에 도움을 주고, 언어의 철학을 이해한다면 그 언어를 쓰기도 쉬워진다.

덧붙여, 프로그래밍 언어에 대해 왜 그렇게 열심히 공부하냐는 사람도 있는데, 이는 작문법을 왜 그렇게 열심히 공부하냐는 질문과 비슷하다. 작문을 잘하기 위해서는 물론 작문을 많이 해보아야겠지만, 다른 사람들이 이미 고민해둔 좋은 작문방법이 있다면, 시행착오를 통해서 배우는 것보다는 이를 공부하는 것이 훨씬 시간이 절약되기 때문이다. 게다가, 작문법에는 언어간의 벽을 뛰어넘는 무언가가 있어서, 다른 언어에 대해서도 적용되는 경우가 있다. 반대로, 언어간의 벽을 뛰어넘지 못하는 철학적인 요소도 작문을 하는데에 필요하다.

물론, (프로그래밍을 처음 배우는 모든 사람들에게 항상 얘기하듯이) 작문법만 공부해서는 절대로 문장가가 될 수 없다는 점을 유념해야할 것이다. 역사 공부도 중요하고 철학 공부도 중요하지만, 실제로 다작을 해보는 것처럼 중요한 것은 없다. 마찬가지로 어느 정도 프로그래밍에 대한 지식을 익히고 나서는, 실제로 프로그래밍을 해보지 않는 한, 절대로 더 높은 단계로 올라설 수가 없다.

More Exceptional C++ 더 읽기"

Object Thinking (continued, Chapter 3)

Object Thinking

현재 진행 상황은 chapter 5를 마치고 chapter 6를 읽는 중. 11월까지 끝내려고 마음 먹었는데, 그렇게는 안되는 것 같다. 1-2월 정도까지 읽어야하려나… 같이 읽던 ‘리눅스 커널의 이해’는 잠시 쉬고, 이 책에 집중을 해봐야겠다.

그건 그렇고, 상당히 재미있게 보고 있다. 책을 사고나서 내용을 훑고 나서는 그냥 ‘OO introduction 책이잖아?’ 하고 쉽게 보았는데, 지금까지만으로도 몇몇 중요한 meme을 도입하게 만들어, 내 mindset에 상당한 변화를 주고 있다. 번역이 되어서 널리 읽히게 되면 참 좋겠다는 생각이 든다. 그 중에서 가장 인상적인 chapter가 바로 chapter 3이었다.

Chapter 3: From Philosophy to Culture는 object culture를 소개하고 있다. object culture의 특성을 간단히 옮겨보면,

  • 정확하게 정해진 형식성보다는 질서를 가진 비형식성으로의 위임
  • 전체를 바라보기 보다는 지역적인 초점 (local focus)
  • 최소한의 디자인/프로세스 문서의 생산
  • 중앙 집중식 관리 스타일보다는 협동적
  • 제어보다는 조정과 협조에 기반한 디자인
  • 구조화된 개발보다는 빠른 프로토타이핑
  • 체계적인 것보다는 창의적인 것에 가치를 둠
  • 외부의 과정에 따르기보다는 내부적인 능력에 따름

정확하게 이해할 필요는 없고, 대충의 감만 잡으면 될 것 같다. 뒤에서 계속 반복되면서, 저절로 익숙해지는 일종의 “문화”이기 때문이다.

Four Presuppositions

다음으로 얘기하는 것은 object thinking (object culture의 기반이 되는?) 4가지 전제조건이다. 역시 그대로 옮겨보자.

  • 모든 것은 object이다.
  • 문제 영역(problem domain)을 시뮬레이션하면 object를 발견하고 정의할 수 있다.
  • object는 조합할 수(composable) 있어야 한다.
  • organizational paradigm에서 분산된 협동과 통신이 계층적이고 중앙집중적인 제어를 대체해야한다.

각각을 간단하게 설명해보면,

“모든 것은 object이다”라는 가정은 아무리 복잡한 영역(domain)이라고 하더라도, decomposition을 거치면, 상대적으로 적은 수의 object들만이 남는다는 생각이다. 일종의 원자론이다. (모든 물건들은 100개 남짓한 종류의 원자들로 이루어져있다라는 생각과 비슷하고, 이 책에서도 그러한 비유를 활용한다.) 그렇다면 object란 무엇인가? 이 질문에 대한 정확한 답은 더욱 뒤에 나온다.

위에서 얘기했듯이, object가 발생하는 이유는 decomposition이라는 과정을 거치기 때문이다. decomposition은 abstraction을 적용함으로써 수행된다.이러한 abstraction은 특정한 관점(aspect)을 선택하고 그것에 초점을 맞추는 것을 필요로 한다. 이러한 관점(aspect)의 차이가 decomposition을 수행할 때, 그 결과물들 사이의 차이를 구분하는 기준이 된다.

전통적인 컴퓨터 과학자들과 소프트웨어 엔지니어들은 복잡한 domain을 모듈로 decomposition할 때, data와 function (algorithm)으로 분리하는 방법을 사용했다. (CS101을 열심히 배웠다면, 아마 dijkstra의 ‘프로그램’의 정의도 기억날 것이다) 이 때, data와 function은 가상적인 기준이어서 자연스러운 이음매가 아니고, 이 때문에 소프트웨어 엔지니어링의 거의 모든 문제가 발생한다고 얘기한다. 다시 말하면, 프로그램을 data와 function으로 분리하는 것은 일반적으로 우리가 세계를 이해하는 방식과 너무 틀리다는 것이다.

그래서 제안하는 decomposition abstraction의 기준은 바로 행동(behavior)이다. 인간은 세계를 이해할 때, 분류를 하고, 분류를 하기 위해서는 차이를 인식해야하는데, 차이를 인식할 때의 기준은 행동(behavior라는 주장을 하고 있다. object thinking에서는 이처럼 실세계에서의 decomposition 방식을 소프트웨어 개발에 도입하기 때문에, 당연히 소프트웨어 개발자는, 해당 영역의 전문가(domain expert)의 얘기를 들어야한다. 이는 문제 영역(problem domain)의 시뮬레이션이 곧 object의 decomposition이라는 주장으로 이어진다.

“object를 잘 조합할 수(composable) 있다”면 decomposition 역시 잘 된 것이다. 이러한 조합성(composability)은 재사용성(reusability)과 유연성(flexibility)을 포함한다. 이를 획득하기 위해서는 object의 행동을 발견하고 일반화하는 과정이 필요한데, 이것 역시 나중 chapter로 설명을 미룬다.

실세계에서도 그런 것처럼 object는 자율적이어야 한다. 중앙 집중적인 제어는 쪼개서 분산시킬 수 있다.

OO에 익숙하지 않은 사람이 가장 쉽게하는 실수들이 이러한 4가지 조건들에서 자주 발견된다. 자주 볼 수 있는 것 중의 하나는 객체가, problem domain이 아니라 implementation domain의 동작을 노출하는 것이다. 비슷한 것으로는 클래스나 메서드의 이름 problem domain에 대해서 제대로 파악이 안되어서 implementation domain의 용어와 혼재되어 있는 것이다. 다른 한가지는 중앙 집중적인 제어다. 그 사람이 짓는 클래스의 이름에 “*Manager”라는 이름이 많다면 이를 의심해볼 수 있다. 또 다른 예로는, 한 object는 거의 자신의 동작을 가지지 않고, 다른 object가 해당 object의 상태를 심하게 바꾸는 방식이 있다. 분명 OO 언어를 사용해서 만들었겠지만, data/function의 decomposition에 지나지 않는 예다. (이러한 실수들에 대해서 따로 글을 써 볼 예정이다.)

Object Principles – Software Principles

그 다음으로는 Witt, Baker, Merrritt의 Software quality를 정의하는 axiom들을 소개한다.

  • Axiom of separation of concerns: 복잡한 문제를 여러 간단한 문제들로 나누어서 해결한다.
  • Axiom of comprehension: 인간의 인식한계를 고려한다.
  • Axiom of translation: 정확도는 동등한 문맥들간의 이동에 영향받지 않는다.
  • Axiom of transformation: 정확성은 동등한 component간의 교체에 영향받지 않는다.
  • Principle of modular design: axiom of separation of concerns
  • Principle of portable designs: axiom of translation
  • Principle of malleable designs: axiom of transformation
  • Principle of intellectual control: abstraction의 적절한 사용
  • Principle of conceptual integrity

소프트웨어 엔지니어링의 지극히 일반적인 얘기들이지만, 가만히 살펴보면, object thinking과 object는 위의 목적에 상당히 적합하다는 것을 알 수 있다.

그리고 한가지 더, Fred Brooks의 유명한 paper인 ‘No Silver Bullet: Essence and Accidents of Software Engineering’에서 언급한 소프트웨어 개발에 있어서의 본질적인 어려움을 소개하면서, object thinking이 이러한 문제를 해결하고 있다고 주장한다.

  • Complexity: 소프트웨어는 인간이 만든 어떤 다른 체계보다도 복잡하다.
  • Conformity: 소프트웨어는 실제 세계에 부합해야한다
  • Changeability: 세계가 변화하면 소프트웨어도 변화해야한다; 세계는 자주 변화한다.
  • Invisibility: 소프트웨어(e.g. 실행하는 프로그램)를 실제로 볼 수 없으므로, 생각하기도 힘들다.

위의 전제조건에서도 보았듯이, object thinking에서 object는 실세계를 반영해야하므로, 당연히 이러한 어려움에 대한 가장 직접적인 대응책일 수 밖에 없다.

Cooperating Cultures

계속 비판해온 전통적인 컴퓨터 과학과 소프트웨어 엔지니어링을 절대적으로 거부하는 것은 아니라고 얘기한다. 그리고, 각각의 culture의 영역을 구분하는 기준을 제시한다.

Natural world – Deterministic world의 축과 Comprehension – Implementation의 축을 교차시키고, Object paradigm은 Natural world/Comprehension의 영역에, Computer science paradigm은 Deterministic world/Implementation의 영역에 둔다. 두 paradigm/culture는 적용하는 영역이 다른 것이다. 흥미로운 것은 deterministic world의 예로, hardware, discrete module, algorithm, small-scale formal system 등을 들고 있다는 것이다. 대체로 data와 function의 구분이 불가피한 영역들이다. 그렇다면 OS를 개발할 때는 대체로 computer science paradigm을 적용하는 것이 좋은가? 약간 더 hardware로부터 멀리 있는 system programming은 어떠한가? 모호하긴 하지만, OS의 상위 layer나 system programming 수준에서는 OO paradigm을 적용하는데에 무리는 없으리라고 생각한다.

Object Thinking (continued, Chapter 3) 더 읽기"

Understanding the Linux Kernel (2nd Edition) (continued)

Understanding the Linux Kernel (2nd Edition) (continued)

8장을 마친 후에, 이어서 3-6, 9-11장을 읽었다.

3장은 프로세스와 프로세스 전환, 4장은 x86계열에서의 인터럽트 처리 방식과 리눅스에서의 인터럽트 처리 방식, 5장은 커널 동기화에 필요한 여러가지 primitive들, 6장은 역시 x86 계열에서 사용되는 하드웨어 타이머들의 소개와 리눅스에서의 활용 방식, 9장은 시스템 콜이 처리되는 방식, 10장은 시그널의 처리 방식, 11장은 프로세스 전환 시, 스케줄러 정책을 다루고 있다.

나머지 장들은 디스크 액세스로부터 파일 시스템, swapping에 관련된 것이어서 11장을 읽고 난 후엔 거의 다 읽은 거겠지 하고 생각했는데, 아직도 반이나 남아있다. 비슷한 속도로 읽으면 복학하기 전에는 끝낼 수 있을 듯하다.

읽으면서 든 느낌은 kernel 구현은 보통의 프로그램 처럼 하나의 behavior를 위한 logic이 잘 모여있기 보다는 – 각종 하드웨어 이벤트 들에 대해서 multiplexing되어 있어서 – 이곳 저곳에 얇게 퍼져있고, 따라서 직관적으로 이해하기는 좀 힘들다는 것이었다. 물론 이 책이 그러한 복잡함을 이해하는 데, 큰 도움이 되겠지만 말이다.

Understanding the Linux Kernel (2nd Edition) (continued) 더 읽기"

"Programming Ruby" 번역

딥뿔군루비 사용자 모임을 만들고 번역 프로젝트를 시작하면서, 현재로서는 루비 언어의 바이블 격인 “Programming Ruby”의 번역 작업에 참여하게 되었다. 번역하고 보면 몇장 되지도 않는 분량을 한 6개월 가량 끌어온 것 같은데 (남들은 2-3개씩 번역했는데!!!), 어쨌든 끝나고 나니 좀 후련하다. 끝난다고는 해도, 아직 초벌 번역이라, 용어들의 inconsistency도 있고, 번역어스러운 문장이 한 둘이 아니다. docbook export를 지원하는 dbwiki를 사용했는데, 사용법에도 좀 더 익숙해져야할 것 같다.

국내 개발서 번역에 대한 상당한 비판자였고, 이 블로그에도 그 비판을 아끼지 않았던 것 같은데, 직접 번역을 해보니 시간도 많이 들고, 어렵긴 어려운 것 같다. 한국어에 없는 단어라든가, 영어에만 국한되는 유머와 같은 번역 자체의 어려움도 있지만, 컴퓨터 용어의 번역은 이미 그 용어가 영어의 철학에 빚지고 있는 탓에, 번역하기 어려운 경우도 있는 것 같다. 예를 들어, 객체의 메서드를 호출하는 것을 메시지를 보내는 개념(OO에서 일반적인 object에 대한 metaphor이다)으로 자주 설명하기 때문에 ‘receiver’같은 것을 번역해야할 경우가 발생한다. 난 그냥 문맥에 따라 ‘객체’로 번역했지만, ‘수신자’라고 해버리면 곤란한 것이다.

보통 이런 language tutorial을 읽으면 금방 잊어버리는데, 번역을 하고 나니, 부수적인 효과로 내가 번역한 것에 대한 내용은 잘 안잊어버리게 된 감이 있다. 좀 더 열심히 해서 다른 장도 번역해볼 껄 그랬나.

다음은 내가 맡은 “클래스, 객체, 변수” 장의 번역.

http://doc.rubykr.org/dbwiki/index.php/PR%20%C5%AC%B7%A1%BD%BA%2C%20%B0%B4%C3%BC%2C%20%BA%AF%BC%F6

"Programming Ruby" 번역 더 읽기"

C++ Standard Library Technical Report Draft Update

C++ Standard Library Technical Report의 draft.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1711.pdf

(위 링크를 통해 다운받는 것이 현재 매우 느리므로, 본인에게 요청하면, 직접 보내줄 수 있다.)

n1540에서의 커다란 변경사항이라면 fixed size sequence인 array container가 추가되었다는 것이다. 기존부터 알려져있었지만, 특이할만한 사항은, array container 역시 aggregate라서 일반적인 array 처럼 initializer list를 사용한 초기화가 가능하다는 것이다. 즉, 다음과 같은 문법이 가능하다.

array a = { { 1, 2, 3, 4, 5 }}; // boost
array a = { 1, 2, 3, 4, 5 }; // tr1

기존 Standard Library 상의 container들의 불편한 점 중의 하나가 multi-dimension container를 초기화하기가 매우 불편했다는 것인데, 이것으로 해결이 어느 정도 가능했으면 한다.

몇몇 compiler 구현에서는 TR1의 몇몇 component들을 제공하고 있지만, 아직 boost쪽에서도 논의 중인 정도이므로, private/proprietary solution으로 TR1의 container들을 손수 구현해보는 것도 의미있고, 재미도 있는 일일 것 같다.

C++ Standard Library Technical Report Draft Update 더 읽기"

boost 1.32 release draft

From http://article.gmane.org/gmane.comp.lib.boost.devel/112562/

곧 release될 boost 1.32의 변경사항들이다.

매우 유용할만한 Multi-index containers나 Program Options, 새로 제안된 iterator 개념을 구현한 Range Library,  C++에 없어서 불편했던 string utility – String algorithm, stream과 연동해서 여러 sink로의 serialization방법과 filtering 방법을 제공하는 Serialization framework가 새로 추가되었다.

http://www.meta-comm.com/engineering/boost/1_32_0_draft/

http://www.meta-comm.com/engineering/boost/boost_1_32_0.tar.bz2
http://www.meta-comm.com/engineering/boost/boost_1_32_0.tar.gz
http://www.meta-comm.com/engineering/boost/boost_1_32_0.zip

New Libraries

  • Assignment Library: Filling containers with constant or generated data has never been easier, from Thorsten Ottosen.
  • Minmax Library: Standard library extensions for simultaneous min/max and min/max element computations, from Hervé Brönnimann.
  • Multi-index Containers Library: Containers with multiple STL-compatible access interfaces, from Joaquín M López Muñoz.
  • Numeric Conversion Library: Optimized policy-based numeric conversions, from Fernando Cacciola.
  • Program Options Library: Access to configuration data given on command line, in config files and other sources, from Vladimir Prus.
  • Range Library: A new infrastructure for generic algorithms that builds on top of the new iterator concepts, from Thorsten Ottosen.
  • Serialization Library: Serialization/de-serialization of arbitrary C++ data structures to various formats including text, binary, and xml, from Robert Ramey.
  • String Algorithms Library: Collection of string related algorithms for case conversion, trimming, find/replace operations and more, from Pavol Droba.
  • Tribool: 3-state boolean type library, from Doug Gregor.

Updated Libraries

boost 1.32 release draft 더 읽기"

OOM killer & Overcommit

Problem

Linux 시스템의 (swap을 포함한) 메모리가 모두 소진된 상태에서 중요한 프로세스(e.g. server app)가 OOM killer에게 죽는 현상이 발생할 수 있습니다. OOM killer가 무엇이고, 중요한 프로세스를 살아남게 하려면, 어떻게 해야할까요?

OOM killer is…

http://www.win.tue.nl/~aeb/linux/lk/lk-9.html#ss9.6

OOM(Out-Of-Memory) killer는

– a) 특정 (메모리가 부족한) 상황에서 동작해서,

– b) 특정 알고리즘에 의해 프로세스를 선택,

– 해당 프로세스를 kill 해서 메모리를 확보합니다.

OOM killer & Overcommit

위의 page에서는 OOM의 존재 자체가 일종의 버그라고 말합니다.

linux는 overcommit, 즉, 실제로 필요로 하는 메모리보다 더 많은 메모리를 (가상적으로) 할당하는 정책을 사용하기 때문에,

OOM killer가 필요한 상황이 발생하는 것입니다. 이러한 정책을 optimistic memory allocation이라고 부르구요. (반대로 pessimistic이 있겠죠)

Linux는 ‘프로세스는 자신이 요청한 메모리 양을 모두 쓰지 않는다’라는 낙관적인 가정을 하기 때문에 이렇게 부릅니다.

Linux는 최대한 할당은 늦게 하고, 한번 할당되면 계속 사용한다는 가정을 하고 VM 시스템을 만들었습니다.

brk() system call을 통해서 heap 크기를 늘리려고 시도할 때 (즉, virtual address space를 할당할 때)는 일단 허용하고,

실제로 memory frame이 할당되는 시점을 사용자 프로세스가 실제로 해당 메모리에 접근해서 fault가 일어날 때로 미루어서 이러한 정책을 구현합니다.

물론 OS는 사용자 프로세스들에 할당된 address space의 총합과 자신이 할당할 수 있는 memory frame의  전체 크기를 알기 때문에 overcommit을 방지할 수 있습니다.

Linux 2.6에서도 가능한 것 같습니다. /proc/sys/vm/overcommit_ratio를 조정해서, 둘 사이의 비율을 조정할 수 있습니다.

root@www src # uname -a
Linux www.lastmind.net 2.6.8-rc1 #1 Thu Jul 15 21:11:46 KST 2004 x86_64 4  GNU/Linux
root@www src # cat /proc/sys/vm/overcommit_ratio
50

이러한 정책은 어떻게 보면 매우 비합리적으로 보일 수도 있지만, 성능을 올리는데 효과가 있다고 합니다.

(예를 들어, 프로세스 fork시의 COW 정책도 일종의 overcommitting이라고 하는군요.)

OOM killer is …bad guy?

http://www.kerneltraffic.org/kernel-traffic/topics/OOM_Killer.html

kerneltraffic쪽의 page들을 보면, OOM killer가  a)와 b) 단계에서 사용하는 algorithm들에 문제(버그?)가 많았던 모양입니다.

특히 b)의 경우에는 heuristic일 뿐이라서, 중요한 프로세스와 아닌 프로세스를 구분하지 못하기 때문에,

데스크탑 환경이 아닌 서버 환경에서는 매우 치명적일 수 있습니다. 그 외에도 deadlock 같은 버그 문제도 보이는군요.

그래서 그런지 2.4.23에서 OOM Killer는 빠졌습니다만,

http://www.kerneltraffic.org/kernel-traffic/kt20031214_245.html#6

http://kerneltrap.org/node/view/1010

http://kerneltrap.org/node/view/1017

http://kerneltrap.org/comment/reply/1754

다시 그 필요성 때문에, 2.4.24-pre1에서 OOM killer를 kernel compile option(CONFIG_OOM_KILLER)의 형태로 추가했다고 합니다.

문제들은 계속 수정되는 것 같습니다만, b) algorithm이 heuristic라서 발생하는 문제는 여전한 것 같습니다. ^^;

debian의 kernel-image-2.4.26-1-686-smp의 image는

CONFIG_BINFMT_MISC=m
# CONFIG_OOM_KILLER is not set
CONFIG_PM=y

와 같이 OOM killer가 기본적으로 꺼져있군요.

OOM killer algorithm

mm/oom_kill.c를 보면 OOM killer의 코드가 나옵니다.

 *  The routines in this file are used to kill a process when
 *  we’re seriously out of memory. This gets called from kswapd()
 *  in linux/mm/vmscan.c when we really run out of memory.

kswapd는 kernel thread로 동작하면서, page cache를 유지하고 slab cache를 shrink하고 swapping out을 수행합니다.

http://www.csn.ul.ie/~mel/projects/vm/guide/html/understand/node68.html

a) zone마다 일정 수(pages_high)만큼의 page를 확보하기 위해 try_to_free_pages_zone()을 호출하는데,

shrink_caches()를 호출해서 128K 정도의 메모리를 확보하려고 합니다.

http://www.csn.ul.ie/~mel/projects/vm/guide/html/code/node38.html#SECTION001030200000000000000

이를 수행하지 못할 경우, oom_kill.c의 out_of_memory()를 통해, oom_kill()이 수행됩니다.

이는 physical memory를 swap할 공간도, cache를 shrink할 공간도 없다는 의미입니다.

b)

oom_kill()은 모든 task에 대해 badness()를 계산해서 가장 나쁜(badness()의 결과가 가장 큰) task를 kill합니다.

badness()의 주석을 보면,

/**
 * oom_badness – calculate a numeric value for how bad this task has been
 * @p: task struct of which task we should calculate
 * 
 * The formula used is relatively simple and documented inline in the
 * function. The main rationale is that we want to select a good task
 * to kill when we run out of memory.
 *
 * Good in this context means that:
 * 1) we lose the minimum amount of work done
 * 2) we recover a large amount of memory
 * 3) we don’t kill anything innocent of eating tons of memory
 * 4) we want to kill the minimum amount of processes (one)
 * 5) we try to kill the process the user expects us to kill, this
 *    algorithm has been meticulously tuned to meet the priniciple
 *    of least surprise … (be careful when you change it)
 */

주석을 좀 이상하게 적어놓은 것 같은데, 죽이기에 좋은(Good) task가 kill할 task가 됩니다.

이러한 알고리즘에 따르면,

기본적으로 적은 수의 프로세스를 죽여서 많은 양의 메모리를 확보할 수 있는 heuristic을 쓰는 것을 알 수 있습니다.

3번에서 메모리를 많이 사용하는 innocent는 죽이지 않는다고 했으나,

실제 코드를 보면, 여기서 innocent란, 단순하게 cpu를 많이 사용하는 프로세스를 의미하는 것 같습니다.

또한, super user process이거나 hardware를 access하는 경우 badness point를 1/4로 삭감해줍니다.

Solution

OOM killer가 heuristic에 기반하고 있기 때문에, 중요한 server process가 죽지않는 다는 보장을 하기가 힘듭니다.

(위의 badness() 값을 낮추는 방법들을 전부 쓰더라도)

하지만, OOM killer를 쓰지 않는다고 하더라도, 특정 프로세스가 종료할 때까지 기다리는 수 밖에 없고,

(malloc으로 할당 받은 메모리는 대체로 다시 반납하지 않습니다.)

page fault handler에서 page frame을 할당받지 못하면, init를 제외한 해당 task는 kill 되기 때문에,

OOM 상황에서는 어차피 치명적인 상황이 발생합니다.

따라서, OOM 상황이 발생하지 않도록 노력하는 것이 중요할 것 같네요.

server 어플리케이션의 경우에는 대체로 자신이 사용하고 있는 메모리 양을 알고 있으므로 이에 대한 제약을

어플리케이션 수준 또는 시스템 수준(ulimit)에서 가하는 것도 괜찮은 방법이라고 생각합니다.

그리고 메모리 바운드 어플리케이션이라면 대부분 swapping out 되는 것을 원하지 않을 것이므로,

page에 lock을 거는 방법을 생각해볼 수도 있겠네요. (physical page frame이 부족할 경우, 자동적으로 실패하겠죠)

OOM killer & Overcommit 더 읽기"

Extreme Programming Explained, Understanding the Linux Kernel, Object Thinking

Extreme Programming Explained: Embrace Change

XP의 창시자인 Kent Beck이 쓴 XP에 관한 책이다. XP를 공부할 때 처음으로 읽어야할 책이 바로 이 책이다. 200 페이지도 채 안되는 분량의 책은 매우 잘 쓰여진 책이다. 맨 먼저 해결하려는 문제를 정의한 후, 문제에 관련된 변수들을 파악한 후, 추구하는 가치와 기본 원리를 설정한 후 (문제의 해결방법에 있어서, 서로 충돌하는 가치가 있을 때 중요한 단계이다), 이 가치를 달성하기 위한 방법을 제시하고, 이 방법을 실제로 적용할 때의 이슈를 논의한다. 책에서만이 아니라 실제 문제에 있어서도 이러한 접근을 하면, 쓸데없는 혼란을 야기하지 않고 문제를 해결할 수 있다. 또, 자신만의 문제를 해결하기 위해서 뿐만이 아니라 다른사람과 문제와 해결책에 관해 커뮤니케이션할 때도 유용한 패턴이라고 볼 수 있다. (가끔씩 주변을 보면, 문제를 정의하지 않고도 해결법을 찾으려고 하거나, 문제를 알려주지도 않고 해결법을 제시하는 사람들을 볼 수 있다. 선문답이 되면 행복한 케이스지만, 동문서답이 되면 곤란하다.)

다시 XP 얘기로 돌아가서, Kent Beck이 제시하는 소프트웨어 개발 프로젝트의 문제는 바로 Risk이다. 즉, 스케줄의 변경, 프로젝트의 취소, 소프트웨어 결함, 요구사항 변경, 리소스 변경 등이 소프트웨어 실패의 가장 큰 원인이란 것이다. (경험적으로, 이에 전적으로 동의한다) 그렇다면, 우리가 이걸 해결하기 위해서 무엇을 할 수 있는 가를 봐야할 것이다. Kent Beck은 소프트웨어 개발 프로젝트의 ‘Four Variables’로 Cost, Time, Quality, Scope를 제시한다. 일반적으로 Cost와 Time은 우리가 control 하지 않고, (이른바, ‘기획’하는 사람들이 control한다) Quality는 control하기에 너무 어려운 변수이기 때문에, Kent Beck은 Scope에 집중하겠다고 얘기한다.

XP의 네가지 가치(Four Values)는 바로 Communication, Simplicity, Feedback, Courage이다. 기본 원리에는 좀 더 여러가지가 있다. Rapid feedback, Assume simplicity, Incremental change, Embraching change, Quality work.

XP의 해결책이 되는 practice들은 비교적 잘 알려져있다. The Planning Game, Small releases, Metaphor, Simple design, Testing, Refactoring, Pair programming, Collective ownership, Continuous integration, 40-hour week, On-site customer, Coding standards. 이러한 practice는 XP에서 새로 발명한 practice들이 아니라 기존의 Software engineering에서 강조하는 것을 radical하게 강조한 것이다. 다시 말해, code review가 좋은 practice라면 항상 하자는 것이 바로 pair programming이고, simplicity가 좋다면 가장 simple한 design을 하자는 것이 Simple design이라는 식이다. 우리나라말로 하면 좋은 게 좋은 것 정도가 될까? 바로 이러한 아이디어가 ‘Extreme Programming’의 어원이라고 한다.

개인적으로는 Simplicity와 Simple design이 가장 인상적이었다. 물론 현업(-_-;)에 가장 적용하기 쉬운 것이고, 스스로가 ‘design for tomorrow’에 의한 폐해를 많이 겪었기 때문이었다. XP 책을 읽기 전에 이미 약간은 이 practice를 적용해보았고, 결과는 매우 좋았던 것 같다. 개인적인 습관 때문인지 자꾸 복잡한 디자인을 하려는 경향이 있긴 하지만… 계속 remind하고 마인드 트레이닝을 할 필요가 있을 것 같다. 아, 그리고 개인적으로는 기획과 개발이 분리된 job을 그다지 많이 하지 않았기 때문에, 직접 경험한 적은 별로 없지만, 주변 사람들이 자주 불평하는, 기획이 계속 requirement를 변경하거나 기획과 개발의 경계가 불명확한 경우의 괴로움을 XP는, 깔끔하게 해결하고 있는 것 같다. Planning Game을 통한 role의 명확한 분리와 Small release로 인한 risk의 감소가 바로 그것이다. Shared code ownership도 매우 좋은 practice이긴 하지만, 실제 우리 팀에서는 중간 정도의 형태를 취하고 있는 것 같다. product의 경우에는 따로 ownership을 가지고 공유하는 라이브러리의 경우에는 shared ownership 정도가 되는 것 같다. 이렇게 되면 갑자기 다른 사람이 고쳐서 동작하지 않는다는 등의 약간의 리스크는 있지만, Testing으로 극복을 할 수 있도, 이 때에 얻는 개발 속도의 장점은 매우 큰 것 같다. 그리고 On-site customer도 회사에서 자주 보는 communication overhead를 상당히 줄여줄 것 같은데, 우리나라에서 자주 보이는, 팀 간의 알력이 강하게 존재하는 조직 구조에서는 실현하기가 상당히 힘들 것 같다. 더구나 manager들이 깨어있고, 같은 이익을 향해 달려간다는 마인드를 가질 수 있으려면 조직의 크기가 클 수록 불리한 반면, 충분한 인력을 확보할 수 없는 작은 조직의 회사라면 다시 불리한 면도 있는 것 같다.

Agile software development methodology가 상당히 유행하고 있는데, XP가 아닌 다른 방법론 – FDD 등의 방법론들도 한번 살펴보고 싶다.

Understanding the Linux Kernel (2nd Edition)

영문판이 아니라 한글판을 읽고 있다. 2.2 버전을 다룬 1판을 사둔 채 버려두고 있다가 2.4 버전을 다룬 2판도 역시 묵혀오고 있다가, 추석 때 집에 내려가서 읽기 시작했다. 내용은 말그대로 리눅스 커널의 구현에 대한 내용으로, 특히 x86 계열에서의 구현에 집중하고 있다. (때문에 x86에 관한 내용도 꽤 나온다.)

현재, 1장의 introduction을 읽은 후, VM 파트를 따라서 2장, 7장을 읽고 8장을 읽고 있는 중이다. 2장 ‘메모리 주소 지정’은 IA-32 매뉴얼에도 나오는 x86 시스템에서의 segmentation, hardware paging, cache, TLB 등을 다루고 있다. 모호하게 이해하고 있던 부분을 (특히 OS 레벨인지 하드웨어 레벨인지의 구분, ‘logical address’와 ‘linear address’의 용어 구분) 말끔하게 해소한 것 같다. 7장은 커널 상의 메모리 관리를 다루고 있다. physical memory와 linear address space의 관리를 다루고 있다. 8장은 커널이 아니라 사용자 프로세스에게 할당되는 메모리를 다루고 있다. 아마도 프로세스에게 할당되는 linear address space의 관리와 page fault handling을 통해 page frame (physical memory)을 할당하는 방법을 다루고 있다. 여기까지 읽은 후에는 3장으로 돌아가서 프로세스에 대한 내용을 읽을 생각이다.

약간의 번역 inconsistency가 눈에 띄지만 (용어의 번역 여부 e.g. TLB/변환참조버퍼) 번역 퀄리티는 만족스러운 편이며, 내용도 어느 정도 OS에 관심을 갖고 있던 사람이라면 그리 어렵지는 않은 정도. 침대 머리 맡에 놓고, 자기 전에 살짝 조금씩 봐주고 있다. 시스템 프로그래머의 길을 간다면 커널의 이해는 거의 필수적이므로 이를 위해 볼만한 책 중의 하나 일 것 같다.

참고를 위해 언급하자면, 물론 다른 고전적으로 유명한 책들도 있다. Bach의 The UNIX Operationg System (너무 오래된 감이 있음)이나 UNIX Internal (괜찮은 듯), The Design and Implementation of the 4.4 BSD Operating System (안봐서 모름), Solaris Internal (안봐서 모름).

Object Thinking

물론 자기네 회사에서 나온 책이니 그렇겠지만, MSDN blog들에서 워낙 칭찬하던 책이라, 이 책을 처음 접하게 되었다. OOT에서 얘기하는 Object design의 기본적인 기법이나 pattern 같은 것들을 어느 정도 알고 있고, 또 사용하고 있지만, 내가 디자인한 OO 코드를 반대하는 사람에게 나의 디자인을 설득할 자신까지는 없었다고 할까. 기껏해야 OO에서 널리 쓰이는 기법이다 정도?의 argument로는 스스로가 납득할 수가 없었다. 따라서, 이 책을 산 목적은 Object-Oriented Technology의 역사/철학적인 백그라운드를 갖기 위해서였다. 실제로 이 책은 OOT의 역사와 철학, 용어들을 설명하는 non-formal한 OOT의 introduction book 정도로 생각하면 될 것 같다.

Preface, Introduction을 막 마친 상태인데, 11월까지는 끝낼 생각이다. 여기서 빠뜨릴 수 없는 얘기가 Preface/Introduction에서 이 사람은 범상치 않은 얘기를 하고 있다는 것이다. Preface에서는 Booch의 말을 언급하면서 OO란 decomposition에 대해 다르게 생각하는 방식/다른 가치/다른 문화라고 얘기한다. 이어서, formalism/Software engineering과 hermeneutics-postmodernism/XP/agile methodologies/behaviroal objects의 철학을 서로 대조하고 있다. Introduction에서는 Software crisis에 대해서 언급하면서 이를 해결하기 위해서 학계가 선택한 현재의 Software engineering은 process와 methodology에 주안점을 두었지만, 이는 현재 실패했다고 한다. 따라서, tool이나 process나 methodology를 만드는 것이 아니라, 원래 ‘Software Crisis’의 해결책으로 제시되었던 ‘Better people’을 만들어내야한다고 주장하고 있으며, 자신의 책이 ‘Better people’을 만드는 데 도움을 주는 책(중의 하나)이라고 주장하고 있다.

참고로, 얼마전에 slashdot에 review가 올라왔던 Organizational Patterns of Agile Software Development에서는 이렇게 얘기하고 있다.

What makes a software development project succeed? It’s not language or tools or process. It’s not a simple as people; even great programmers sometimes find themselves associated with disasters. In some sense, a successful project is the same thing as a successful organization; but what makes those? We need an anti-Dilbert. In Organizational Patterns of Agile Software Development, James O. Coplien and Neil B. Harrison lay out the results of their research on the subject; what they found, helps.

즉, 소프트웨어 개발 프로젝트를 성공하게 하는 건, 툴이나 프로세스도, 사람도 아니라 바로 조직이라고 얘기하고 있다. “Object Thinking”에서 주장하는 “사람”과는 또 다른 주장인 것이다. 누구 말이 맞는 것일까? 서로 다른 철학과 서로 다른 주장이 난무하는 이 분야는 아직 pseudo-engineering의 분야이다.

Extreme Programming Explained, Understanding the Linux Kernel, Object Thinking 더 읽기"