컴퓨터 커널(kernel)에 대해서 알아보자
컴퓨터 과학에서 커널(kernel)은 운영 체제의 핵심 부분으로서, 운영 체제의 다른 부분 및 응용 프로그램 수행에 필요한 여러 가지 서비스를 제공한다. 핵심(核心)이라고도 한다.
커널의 역할
커널은 운영 체제의 핵심 부분이므로, 커널의 역할 역시 운영 체제의 핵심 역할이라 할 수 있다.
보안
커널은 컴퓨터 하드웨어와 프로세스의 보안을 책임진다.
자원 관리
한정된 시스템 자원을 효율적으로 관리하여 프로그램의 실행을 원활하게 한다. 특히 프로세스에 처리기를 할당하는 것을 스케줄링이라 한다.
추상화
같은 종류의 부품에 대해 다양한 하드웨어를 설계할 수 있기 때문에 하드웨어에 직접 접근하는 것은 문제를 매우 복잡하게 만들 수 있다. 일반적으로 커널은 운영 체제의 복잡한 내부를 감추고 깔끔하고 일관성 있는 인터페이스를 하드웨어에 제공하기 위해 몇 가지 하드웨어 추상화(같은 종류의 장비에 대한 공통 명령어의 집합)들로 구현된다. 이 하드웨어 추상화는 프로그래머가 여러 장비에서 작동하는 프로그램을 개발하는 것을 돕는다. 하드웨어 추상화 계층(HAL)은 제조사의 장비 규격에 대한 특정한 명령어를 제공하는 소프트웨어 드라이버에 의지한다.
초기의 커널
초창기의 컴퓨터에서 운영 체제 커널은 필수적인 것이 아니었다. 초기의 프로그램은 하드웨어 추상화나 운영 체제의 지원을 받지 않고도 컴퓨터만으로 불러들인 다음 실행될 수 있었으며, 이것은 초창기 컴퓨터들의 일반적인 운영 방식이었다. 다른 프로그램을 실행하기 위해서는 컴퓨터의 전원을 껐다가 켬으로써 다시 입력자료를 읽어들여야 하는 방식이었다. 이러한 과정이 반복되면서 사람들은 로더와 디버거 같은 작은 프로그램들이 상주해 있는 것이, 다른 프로그램으로 교체하거나 새로운 프로그램을 개발하는 데 유리하다는 사실을 알게 되었다. 이와 같은 로더, 디버거들이 초기 운영 체제 커널의 기초가 되었다.
종류
단일형 커널(monolithic kernel) - 커널의 다양한 서비스 및 높은 수준의 하드웨어 추상화를 하나의 덩어리(주소 공간)로 묶은 것이다. 운영 체제 개발자 입장에서 유지 보수가 일반적으로 더 어려우나 성능이 좋다.
마이크로커널(microkernel) - 하드웨어 추상화에 대한 간결한 작은 집합을 제공하고 더 많은 기능은 서버라고 불리는 응용 소프트웨어를 통해 제공한다.
혼합형 커널(hybrid kernel) - 성능 향상을 위해 추가적인 코드를 커널 공간에 넣은 점을 제외하면 많은 부분은 순수 마이크로커널과 비슷하다. 수정 마이크로커널이라고도 한다.
나노커널(nanokernel) - 실질적으로 모든 서비스를 책임진다.
엑소커널(exokernel) - 낮은 수준의 하드웨어 접근을 위한 최소한의 추상화를 제공한다. 전형적으로 엑소커널 시스템에서는 커널이 아닌 라이브러리가 단일형 커널 수준의 추상을 제공한다.
커널 별 구조
커널은 컴퓨터 운영체계의 가장 중요한 핵심으로서, 운영체계의 다른 모든 부분에 여러 가지 기본적인 서비스를 제공한다. 비슷한말로는 '뉴클리어스'라는 용어가 있다. 커널은 쉘과 대비될 수 있는데, 쉘은 운영체계의 가장 바깥부분에 위치하고 있으면서, 사용자 명령에 대한 처리를 담당한다. 커널과 쉘이라는 용어는 IBM 메인프레임을 제외하고, 유닉스와 기타 몇몇 운영체계에서 자주 사용된다.
일반적으로, 커널에는 종료된 입출력 연산 등, 커널의 서비스를 경쟁적으로 요구하는 모든 요청들을 처리하는 인터럽트 처리기와, 어떤 프로그램들이 어떤 순서로 커널의 처리시간을 공유할 것인지를 결정하는 스케줄러, 그리고 스케줄이 끝나면 실제로 각 프로세스들에게 컴퓨터의 사용권을 부여하는 수퍼바이저 등이 포함되어 있다. 커널은 또한, 메모리나 저장장치 내에서 운영체계의 주소공간을 관리하고, 이들을 모든 주변장치들과 커널의 서비스들을 사용하는 다른 사용자들에게 고루 나누어주는 메모리 관리자를 가지고 있다. 커널의 서비스는 운영체계의 다른 부분이나, 흔히 시스템 호출이라고 알려진 일련의 프로그램 인터페이스들을 통해 요청된다.
커널을 유지하기 위한 코드는 지속적으로 사용되기 때문에, 보통 커널은 자주 사용되지 않는 운영체계의 나머지 부분에 의해 덮어씌워져 훼손되지 않도록, 보호된 메모리 영역에 적재된다.
커널을 바이오스와 혼동하면 안된다.
OS의 심장이자, OS를 규정짓는 매우 중요한 부분. 하드웨어의 자원을 자원이 필요한 프로세스에 나눠주고, 덩달아 프로세스 제어(태스크 매니저), 메모리 제어, 프로그램이 운영체제에 요구하는 시스템 콜 등을 수행하는 부분으로 운영체제 맨 하부에서 돌아간다. 쉽게 말해, OS를 하나의 기업체로 비유한다면 커널은 인사담당 부서인 셈이다. 현재 많이 사용되고 있는 OS는 커널 위에 여러 가지 레이어를 올린 것. 이렇기 때문에 커널이 날아가게 되면 운영체제를 못 쓰게 된다. 이 커널도 한번씩 오작동 하여 정지할 때가 있는데, 이를 가리켜 커널 패닉이라고 부른다. 물론, 현재는 억지로 볼 수는 있지만, 일반적인 상황에선 꽤나 보기 힘들다.
어쨌든 커널로 운영체제의 정체성을 결정하기에 매우 중요하다고 볼 수 있다. 페도라, 우분투등이 다 리눅스로 묶이는 것도 이들이 리눅스 커널을 사용하고 있기 때문이다.
리눅스 커널이란?
리눅스를 만지면서 커널 커널 하지만 의외로 커널이 뭐야? 라고 물으면 모르는 사람들이 많다. 간단히 정리해보자
커널은 시스템에 존재하는 자원을 효율적으로 관리하는 자원 관리자로, 그 기능을 간단히 살펴보면
프로세서 관리 - 처리 속도를 향상시키기 위해 여러 프로세서를 병렬로 연결하여 사용한다. 시스템에서 동작하는 프로세스도 커널에서는 관리해야할 자원이고, 운영체제의 처리 요구에 맞춰 동작할 수 있도록 각 프로세스에 필요한 프로세서를 효율적으로 할당하고 수행하도록 관리한다.
프로세스 관리 - 운영체제에서는 최소한 하나 이상의 프로세스가 동작한다. 프로세스는 다른말로 태스크라고도 하며, 주어진 일을 수행하는 기본 단위다. 커널은 스케줄러를 이용하여 여러 프로세스가 동작할 수 있도록 각 프로세스를 생성하고 제거하며, 외부환경과 프로세스를 연결하고 관리한다.
메모리 관리 - 각각의 프로세스가 독립적인 공간에서 수행할 수 있도록 가상 주소 공간을 제공한다. 가상메모리를 바탕으로 물리적인 한계를 극복할수 있는 기능을 제공한다.
이외에도 파일 시스템 관리, 디바이스 제어, 네트워크 관리 정도가 있다.
리눅스 커널은 운영체제에서 가장 중요한 부분이다. 프로세서와 시스템 메모리에 상주하면서 디바이스나 메모리 같은 하드웨어 자원을 관리하고, 프로세스의 스케줄을 관리하여 다중 프로세스를 구현하고, 시스템에 연결된 입출력을 처리하는 운영체제의 핵심 역할을 수행한다.
그렇다면 리눅스 커널의 특징은 무엇일까
모놀리식 커널 - 리눅스 커널은 대부분 유닉스 커널과 같은 모놀리식(monolithic)이다. 모놀리식이기 때문에 논리적으로 구분되는 여러 구성요소들이 상호간에 연결되어 동작한다.
비선점형(커널 2.4)과 선점형(커널2.6) - 비선점형 커널은 프로세스의 동작 상태가 사용자 모드에서 커널 모드로 진입하면 외부에서 해당 프로세스를 중지시키지 못한다. 반대로 프로세스가 커널 모드로 동작하더라도 스케줄링 정책이나 다른 외부적인 접근을 통해 프로세스를 강제로 중지시킬 수 있는 경우를 선점형이라고 한다. 2.6커널은 선점형과 비선점형을 선택할 수 있다.
가상 메모리 시스템(VM) - 리눅스 커널은 다양한 플랫폼에서 동작하는 운영체제이므로 i386에서 동작되던 메모리 관리 시스템을 표준화 하여 다양한 MMU 디바이스에 적용할 수 있도록 구성되어있다.
No MMU 지원 - 리눅스 커널은 주로 MMU를 이용한 메모리 관리를 수행하지만 임베디드 시스템에서 사용하는 프로세서의 경우는 MMU디바이스가 없는 경우도 있다. 커널 2.6에서는 MMU가 없는 시스템도 지원한다.
가상 파일 시스템(VFS) - 리눅스에서는 ext2를 비롯 다양한 파일 시스템을 사용할수 있고, 윈도우에서 동작하는 NTFS파일 시스템과 FAT32도 처리할 수 있다.
모듈을 이용한 커널 확장 - 운영 체제가 동작하는 중에도 커널 코드를 추가하거나 삭제할수 있다.
커널 스레드 - 커널 2.4이전에는 매우 제한된 커널 스레드를 지원했지만, 2.6에서부터는 NPTL(Native POSIX Threading Libray)과 NGPT(Next Generation POSIX Threading Package)를 지원한다.
커널은 운영체제의 핵심을 이루는 요소로서 컴퓨터내의 자원을 사용자 프로그램(User Application)이 사용할 수 있도록 관리하는 프로그램이다.
커널은 프로세스, 파일 시스템, 메모리, 네트워크의 관리를 맡는다. 사용자 프로그램은 이러한 기능들을 정해진 규칙에 따라서 커널에 요구하게 되며, 커널은 이러한 요구들을
만족시켜 주도록 구성되어 있다. 사용자 프로그램은 시스템 라이브러리(System Library)의 도움을 받거나 아니면 직접적으로 소프트웨어 인터럽트(Softw are Interrupt)를 이용해서 트랩(Trap)을 걸어 커널에
접근하게 되며, 이러한 모든 접근은 시스템 콜 인터페이스(System Call Interface)를 통하여 이루어진다.
커널은 대부분이 C 코드(Code)로 작성되어 있으며, 프로세스의 구조에 의존적인(Processor Architecture Dependent) 부분들과 속도를 요하는 부분만 기계어 코드
(Assembly Code)로 작성되어 있다. 따라서 커널의 구조에 의존적인(Architecture Dependent) 부분을 고침으로 해서 새로운 프로세스로의 포팅(Porting)이 가능해진다.
커널은 운영체제의 핵심에 해당한다. 커널은 사용자 프로그램과 하드웨어 장치간의 인터페이스를 제어하고, 다중 작업을 지원하려고 프로세스 스케쥴링을 하며, 기타 시스템의 다양한 측면을 관리하는 소스 코드이다. 커널은 시스템에서 동작하는 어떤 개별 프로세스가 아니라, 항상 메모리에 존재하면서 모든 프로세스가 사용할 수 있는 루틴(routines)들의 집합이라고 할 수 있다. 커널 루틴은 여러 가지 방법으로 호출된다. 커널을 사용하는 직접적인 방법은 시스템 호출(system call)을 사용하는 것으로 커널이 호출
한 프로세스를 위해 특별한 코드를 실행한다. 예를 들어, read 시스템 호출은 파일 기술자(file descriptor)로부터 자료를 읽는다. 프로그래머에게는 C 함수처럼 보이지만 read 의 실제 코드는 커널 안에 있다.
커널 코드는 다른 상황에서도 실행된다. 예를 들어, 하드웨어 장치가 인터럽트(interrupt)를 발생시키면 커널 내부의 인터럽트 처리기를 찾는다. 어떤 프로세스가 어떤 행동을 취하고 결과를 기다려야 할 때는 커널이 개입하여 그 프로세스를 잠들게 하고 다른 프로세스가 활동할 수 있게 스케쥴링한다. 마찬가지로 커널은 한 프로세스에서 다른 프로세스로 이동할 때 클럭 인터럽트를 사용하여 프로세스간의 제어권을 신속하게 옮긴다. 다중 작업은 대개 이런 방식으로 이루어진다.
리눅스 커널은 단일(monolithic) 커널 방식으로, 모든 핵심 함수와 장치 드라이버가 커널의 일부다. 일부 운영체제는 장치 드라이버와 다른 코드가 필요할 때 적재되고 실행되는 마이크로 커널(micro kernel) 아키텍처를 사용하고 있다. 따라서 이 코드는 항상 메모리에 있을 필요가 없다. 두 방식에는 각각 장 · 단점이 있다.
대부분의 유닉스 구현에서는 일반적으로 단일 커널 아키텍쳐가 사용되며, 이는 시스템 V, BSD 와 같은 전통적인 커널에서 채택한 방식이다. 하지만 리눅스는(사용자의 명령에 따라 메모리에 적재하거나 빼낼 수 있는) 적재 가능한 장치 드라이버도 지원하고 있다.
인텔 플랫폼에서 동작하는 리눅스 커널은 인텔 x86 프로세서(80386 부터 현재의 펜티엄 4 가지)의 특별한 보호모드 특성을 사용하도록 개발되었다. 특히 리눅스는 보호모드, 기술자 기반의 메모리 관리 정책과 기타 수많은 인텔 프로세서의 향상된 기능을 활용한다. x86 보호 모드 프로그래밍에 익숙한 사람은 이 프로세서가 유닉스 같은 다중 작업 시스템용(사실은 멀틱스의 영향을 받은 것이다)으로 설계된 것을 알고 있을 것이다. 리눅스는 이 기능을 십분 활용한다.
대부분의 현대적인 운영체제와 마찬가지로 리눅스는 다중 프로세서(M ulti Processing) 운영체제다. 메인보드에 하나 이상의 CPU 가 있는 시스템을 지원한다. 이 기능을 통해 동시에(또는 `병렬로`) 다른 프로그램을 서로 다른 CPU 에서 실행할 수 있다. 리눅스는 또한 하나의 프로그램 안에서 메모리의 데이터를 공유하고 있는 `제어 스레드`를 다중으로 생성하는 프로그래밍 기법인 스레드(thread)도 지원한다. 리눅스는 여러 가지 커널-레벨 그리고 사용자-레벨 스레드 패키지를 지원한다. 리눅스의 커널 스레드는 다중 CPU에서 동작하므로, 하드웨어 병렬 처리 능력을 제대로 활용한다고 할 수 있다. 리눅스 커널 스레드 패키지는 POSIC 1003.1c 표준과 호환된다.
리눅스 커널은 필요에 따라 페이징하고, 적재하는 실행 파일을 지원한다. 즉 프로그램 세그먼트 중 실제로 쓰이는 부분만 메모리로 읽어들인다. 그리고 한 프로그램이 동시에 여러번 실행 중일 때에는 프로그램의 복사본 하나만 메모리에 적재한다. 실행 프로그램은 동적으로 링크된 공유 라이브러리를 사용한다. 즉 실행 프로그램들은 디스크에 있는 라이브러리 파일 내의 공용 라이브러리 코드를 공유할 수 있다. 이렇게 하면 실행 파일이 차지하는 디스크 공간을 줄일 수 있다. 또한 라이브러리 코드 복사본 하나가 메모리에 올라가므로, 전체 메모리 사용량을 줄일 수 있다. 물론 공유 라이브러리에 의존하지 않고 `완전한` 실행파일을 가지고 싶은 사람들을 위해 정적 링크 라이브러리도 있다. 리눅스 공유 라이브러리는 실행 중 동적으로 링크되므로, 프로그래머는 실행 파일을 변경하지 않고도 라이브러리 모듈을 자신이 만든 루틴으로 변경할 수 있다.
시스템 메모리를 최대한 활용하기 위해, 리눅스는 디스크 페이징이라는 기능으로 가상 메모리(virtual memory)를 구현한다. 즉 일정량의 스왑 영역(sw ap space) 을 디스크에 할당할 수 있다. 애플리케이션이 머신에 실제 설치되어 있는 물리적인 메모리보다 많은 메모리를 필요로 하는 경우, 리눅스는 사용하지 않는 페이지를 디스크에 스왑시킨다(페이지page란 운영체제가 메모리를 할당하는 단위다. 대부분의 아키텍처에서는 4KB다). 그리고 스왑아웃시킨 페이지에 다시 접근할 때는 디스크에서 페이지를 읽어와 메인 메모리에 다시 넣는다. 이 기능을 통해 큰 애플리케이션을 실행할 수 있고, 동시에 더 많은 사용자를 지원할 수 있다. 물론 스왑으로 물리적인 RAM 을 대신할 수는 없다.
이는 메모리보다 디스크에서 페이지를 읽는 것이 더 느리기 때문이다. 리눅스 커널은 메모리보다 디스크에 자주 접근하는 것을 피하기 위해, 최근 접근한 일부파일을 메모리에 보관한다. 커널은 디스크 접근 캐시를 위해 시스템에 남은 모든 메모리를 사용하므로, 시스템 부하가 적을 때는 여러 파일에 접근해도 메모리에서 재빨리 처리한다. 만약 사용자 애플리케이션이 더 많은 물리적인 메모리를 요구하면, 디스크 캐시의 크기를 줄인다. 물리 메모리를 쓰지 않고 방치하는 경우는 절대 없다.
또한 디버깅을 쉽게 하기 위해 잘못된 메모리 주소에 접근하는 등의 잘못된 연산을 수행한 프로그램의 코어 덤프(core dump)를 발생시킨다. 프로그래머는 프로그램을 실행시킨 디렉토리에 저장된 core 라는 코어 덤프를 사용하여 비정상 종료의 원인을 판단한다.