2008년 12월 13일 : 김기오(gurugio)씨의 Offline study 개진 2008년 12월 15일 : 처음씀
읽기전에
여기서 나오는 용어 및 변수명등은 실제 범용적인 이론책에 나온 용어해석과 다를수도 있습니다. 또한 알고리즘의 기본을 강조하고 이해도를 높이기 위하여 실제 보강되어야 할부분들이 제거되어 소개됩니다.
유래 및 특징
Slab Allocator(슬랩 할당자)는 1994년 Sun Microsystems의 Solaris 2.4라는 운영체제에서 구현된 "Slab allocator"라는 할당전략에서 유래되었습니다.
이 할당전략의 주요 특징으로는 다음과 같은 점이 있습니다.
유지에 필요한 자료구조와 함께 생성자(Constructor), 소멸자(Destructor)를 구현함으로써 일종의 객체로서의 접근을 구현합니다. (하지만 일부 운영체제에서는 객체관점으로 바라보기는 하지만 생성자, 소멸자를 사용하지 않는 경우도 많이 있습니다.)
객체를 불필요하게 반복 초기화 하는 현상을 회피하기 위하여 할당후에 해제되는 객체를 즉각 폐기하지 않고 메모리에 그대로 유지하려는 속성을 가지고 있습니다.
비슷한 크기의 객체를 캐시하는 유사구조를 사용하기 때문에 일반적으로 발생할수 있는 단편화 문제를 해소합니다.
리눅스의 경우 커널에서 사용하는 일련의 구조중에 매우 빈도가 높은 반복할당객체에 대해서 Cache로 바라보고 그에 맞도록 Slab을 구현합니다.
하드웨어 캐시에 정렬될수 있고 컬러링기법이 적용되기 때문에 캐시성능을 높일수 있습니다.
기본구조(Base layout)
다음은 기본적인 Slab Allocator의 기본구조를 그림으로 나타내어 보았습니다.
크게 slab + nft[slab.objects] + object[slab.objects] 구조로 구성됩니다.
예제를 통한 Slab Allocator의 접근
예제에서는 다음과 같은 구조를 설계안(초기화과정: mzslab_init)으로 설정하고 구현하였습니다. 설계안에서는 생성자(Constructor), 소멸자(Destructor)를 고려하였으나 예제코드 구현에서 이 부분은 적절한 객체의 표면화된 예시까지 제시할 필요가 없기 때문에 생략되었습니다.
Slab 자료구조
/*
Copyright (C) JAEHYUK CHO
All rights reserved.
Code by JaeHyuk Cho <mailto:minzkn@minzkn.com>
*/
/* object index의 단위를 나타내는 변수형입니다.
object수가 65536이상인 경우 이것은 좀 키워야 겠죠. */
typedef unsigned short int __mzslab_index_t;
#define mzslab_index_t __mzslab_index_t
#pragma pack(push,8)
typedef struct mzslab_ts {
/* object 의 크기를 나타냅니다. */
size_t object_size;
/* object를 모두 합친 크기를 나타냅니다.
런타임에서 계산할수는 있으나 미리 계산해두는것이 속도가 좋을듯 해서... */
size_t objects_size;
/* object 수를 나타냅니다. */
size_t objects;
/* 첫 object 의 포인터입니다.
이 또한 런타임에 계산 가능하지만 미리... */
unsigned char *entry;
/* 첫번째 해제된 Object 의 index를 저장합니다.
만약 이 값이 objects보다 같거나 크게 되면 할당가능한 object가 없게 됩니다. */
mzslab_index_t f;
}__mzslab_t;
#define mzslab_t __mzslab_t
#pragma pack(pop)
mzslab_t 의 초기화
mzslab_t * mzslab_init(void *s_page, size_t s_page_size, size_t s_object_size)
{
size_t s_index;
mzslab_t *s_slab;
mzslab_index_t *s_nft; /* next free table */
/* 넘겨받은 page의 첫 부분을 slab 구조체로 유지합니다. */
s_slab = (mzslab_t *)s_page;
s_slab->object_size = s_object_size;
s_slab->objects_size =
s_page_size - (sizeof(mzslab_t) +
((((s_page_size - sizeof(mzslab_t)) / s_slab->object_size)) * sizeof(mzslab_index_t)));
s_slab->objects = s_slab->objects_size / s_slab->object_size;
/* 이 시점에서
(s_page_size -
((s_slab->objects *
sizeof(mzslab_index_t)) +
s_slab->objects_size)) 가 0보다 큰값을 같게 되면
넘겨받은 page_size가 slab 구조와 정렬이 제대로 이루어지지 않아서
남은 짜투리 메모리 크기가 됩니다.
효율적인 구현을 위해서는 0이 되도록 해야 겠죠. */
/* 여기서 (&s_slab[1]) 는 slab 의 다음 항목을 가르키게 되므로
NextFreeObjectIndex table(nft) 을 가르키게 됩니다. */
s_slab->entry = ((unsigned char *)(&s_slab[1])) + (s_slab->objects * sizeof(mzslab_index_t));
s_slab->f = (mzslab_index_t)0u;
s_nft = (mzslab_index_t *)(&s_slab[1]);
for(s_index = ((size_t)0u);s_index < s_slab->objects;s_index++) {
s_nft[s_index] = s_index + ((size_t)1u);
}
return(s_slab);
}
댓글을 달아 주세요
댓글 RSS 주소 : http://blog.minzkn.com/rss/comment/300댓글 ATOM 주소 : http://blog.minzkn.com/atom/comment/300