왜 혼란스러워하는지 알 수 있습니다. 다이어그램이 약간 혼란스럽고 실제로 올바르지 않을 수 있습니다.
먼저, 왜 커널이 페이지 레벨 아래에 메모리 할당자를 필요로하는지 생각해 봅시다. 이것은 아마도 여러분이 주로 알고있는 것들 일 것입니다. 그러나 나는 완전성을 위해 그것을 살펴볼 것입니다.
페이지는 메모리 작업의 일반적인 "단위"입니다. 사용자 공간 응용 프로그램이 메모리를 할당하거나 파일을 메모리 매핑하는 경우 일반적으로 여러 컴퓨터 페이지 크기를 얻습니다. 몇 가지 예외가 있습니다. Windows는 CPU의 페이지 크기에 관계없이 64k를 가상 메모리 할당 단위로 사용합니다. 그럼에도 불구하고 이런 식으로 생각합시다.
최신 CPU에서는 사용자 공간 코드와 관련하여 플랫 주소 공간이 있습니다. 이것은 실제로 가상 메모리 시스템에 의해 제공되는 환상입니다. OS는 RAM (또는 스왑 메모리 또는 메모리 매핑 된 파일의 경우 RAM에 전혀 없음)의 어느 곳에서나 페이지를 제공하고이를 연속 가상 주소 공간에 매핑합니다.
이 모든 점은 운영 체제 자체에 대한 몇 가지 특수 사례 (아마도 DMA 버퍼, 부팅시 특수 데이터 구조가 설정 될 수 있음) 및 커널 이미지 자체와는 별도로 운영 체제 커널이 페이지보다 큰 RAM 블록을 관리합니다. 이것은 페이지를 이동하는 한 모든 할당과 할당 해제의 크기가 동일하기 때문에 일을 엄청나게 단순화합니다. 또한 매크로 수준에서 외부 조각화를 효과적으로 제거합니다.
그러나 커널은 자체 데이터 구조를 구현해야하며,이를 위해서는 다른 종류의 메모리 할당자가 필요합니다. 이러한 데이터 구조는 일반적으로 개별 객체의 모음으로 생각할 수 있습니다 (예 : 객체는 "스레드"또는 "뮤텍스"일 수 있음). 이러한 객체의 크기는 일반적으로 페이지 크기보다 훨씬 작습니다.
예를 들어 프로세스의 보안 자격 증명을 나타내는 개체 (POSIX의 사용자 ID 및 그룹 ID 생각)는 16 바이트 정도일 수 있지만 "프로세스"또는 "스레드"는 최대 1kb 크기입니다. 이러한 작은 레코드에 대해 전체 페이지를 사용하고 싶지 않기 때문에 페이지 위에 할당자를 구현하는 것이 좋습니다.
하위 수준 할당 시스템은 페이지 수준 할당 자와 동일한 많은 문제를 충족시켜야합니다. 즉, 멀티 코어 시스템을 포함하여 합리적으로 빨라야하고 조각화를 최소화하고자합니다. 그러나 더 중요한 것은 어떤 종류의 데이터 구조를 저장하고 있는지에 따라 조정 가능하고 구성 가능해야합니다.
일부 데이터 구조는 본질적으로 "캐시 유사"입니다. 예를 들어, 많은 운영 체제는 긴 디렉토리 조회 체인 (유닉스에서 "이름 캐시"또는 "namei 캐시"라고 함)을 피하기 위해 파일 시스템 객체에 대한 경로 이름 캐시를 유지합니다. 이러한 객체는 정확성이 아닌 성능에만 필요하므로 메모리가 부족하고 페이지 프레임을 빠르게 비워야하는 경우 이론적으로 전체 항목을 잊어 버릴 수 있습니다.
메모리가 부족하여 곧 필요하지 않으면 다른 데이터 구조를 디스크로 교체 할 수 있습니다. 그러나 스와핑 또는 가상 메모리 시스템을 제어하는 데이터 구조로 그렇게하고 싶지 않습니다!
일부 데이터 구조는 페널티없이 메모리 내에서 이동할 수 있으므로 (예 : 아무도 포인터를 사용하여 참조하지 않는 경우), 필요한 경우 조각화를 피하기 위해 "컴팩트"할 수 있습니다.
따라서 슬랩 할당 자의 주요 아이디어는 페이지가 동일한 "유형"의 데이터 구조 만 저장해야한다는 것입니다. 이것은 모든 박스를 체크합니다 : 페이지의 각 객체는 같은 크기이므로 외부 조각화가 없습니다. 동일한 "유형"의 객체는 동일한 성능 요구 사항과 동일한 의미를 갖습니다.
덧붙여서, 그것은 할당과 비슷한 이야기입니다. 일부 객체 유형의 경우 해당 객체를 할당하는 데 즉시 사용 가능한 메모리가없는 경우 기다릴 수 있습니다. 열린 파일을 나타내는 객체가 한 예일 수 있습니다. 파일을 여는 것은 가장 좋은 시간에 값 비싼 작업이므로 조금 더 기다리면 크게 아프지 않습니다.
다른 유형의 객체 (예 : 지금부터 특정 시간에 발생해야하는 실시간 이벤트를 나타내는 객체)의 경우 실제로 기다리기를 원하지 않습니다. 따라서 일부 유형의 객체는 초과 할당 (예 : 몇 개의 무료 페이지를 확보)하여 요청없이 요청을 충족시킬 수 있습니다.
기본적으로하는 일은 각 유형의 객체에 고유 한 할당자가있을 수 있도록 허용하는 것입니다.이 할당자는 해당 객체의 요구에 맞게 구성 할 수 있습니다. 이러한 객체 별 할당자를 "캐시"라고 혼동합니다. 객체 유형마다 하나의 캐시를 할당합니다. (예, 일반적으로 "캐시 캐시"도 구현합니다.) 각 캐시는 동일한 유형의 객체 만 저장합니다 (예 : 스레드 구조 만 또는 주소 공간 구조 만).
각 캐시는 차례로 "슬래브"를 관리합니다. 슬래브는 같은 유형의 객체 배열을 포함하는 페이지 프레임입니다. 슬래브는 "full"(사용중인 모든 개체), "empty"(사용중인 개체 없음) 또는 "partial"(일부 사용중인 개체) 일 수 있습니다.
슬래브 할당자는 모든 부분 슬래브에 대한 무료 목록을 유지하므로 부분 슬래브가 가장 흥미로울 것입니다. (전체 슬래브 및 빈 슬래브에는 사용 가능한 목록이 필요하지 않습니다.) 필요하지 않은 페이지 할당을 피하기 위해 먼저 부분 슬래브에서 객체를 할당합니다 (아마도 "가장 가득한"부분 슬래브에서 할당).
슬랩 할당의 좋은 점은 이러한 모든 할당 정책 옵션 (및 메모리 의미론)을 각 종류의 객체에 맞게 조정할 수 있다는 것입니다. 일부 캐시는 빈 슬래브 풀을 보유하고 일부는 그렇지 않을 수 있습니다. 일부는 보조 스토리지로 교체 될 수 있지만 일부는 그렇지 않을 수도 있습니다.
Linux에는 압축성, 캐시 친 화성 또는 원시 속도가 필요한지 여부에 따라 세 가지 종류의 슬랩 할당자가 있습니다. 몇 년 전에 이것 에 대한 좋은 발표 가 있었는데 , 이것은 장단점을 잘 설명합니다.
Solaris 슬랩 할당 자 (자세한 내용 은 백서 참조 )에는 훨씬 더 많은 성능을 제공하기위한 몇 가지 세부 정보가 있습니다. Solaris의 경우, 페이지 프레임 할당을 포함하여 슬래브 할당으로 모든 작업이 완료됩니다. (이것은 크기가 반 페이지보다 큰 객체를 할당하기위한 Solaris의 솔루션입니다.) 슬래브 할당 공간에 슬래브 할당자를 중첩하여 작은 객체를 관리합니다.
Solaris의 일부 객체는 복잡하고 값 비싼 구성 및 소멸 (예 : 커널 잠금이있는 객체)이 필요하므로 "부분적으로 자유"(즉, 구성되었지만 할당되지 않은) 일 수 있습니다. 또한 Solaris는 CPU별로 사용 가능한 목록을 유지하여 사용 가능한 슬랩 할당을 최적화하여 일부 작업이 완전히 대기하지 않도록합니다.
범용 할당을 지원하기 위해 (예 : 컴파일 타임에 크기를 알 수없는 어레이의 경우) 대부분의 매크로 커널 유형 운영 체제에는 객체 유형이 아닌 객체 크기 를 나타내는 캐시가 있습니다 . 예를 들어, FreeBSD는 크기가 2 바이트 (4에서 256) 인 알 수없는 객체에 대한 캐시를 유지 관리합니다.
내가 볼 수있는 것은 슬랩 할당이 다양한 종류의 데이터 요구에 맞게 조정할 수있는 매우 유연한 프레임 워크라는 것입니다. 페이징과 경쟁하지 않지만 보완합니다 (Solaris에서는 페이지 프레임이 슬래브와 함께 할당 됨).
이게 도움이 되길 바란다. 설명이 필요한 것이 있으면 알려주십시오.