Slab Memory Allocator -1- (구조)

 

Slab Memory Allocator

커널은 다음과 같이 3가지 중 하나를 선택하여 빌드되어 사용된다. 서로에 대한 차이점을 나누어 본다.

Slab

  • 커널 메모리 관리의 핵심으로 2007~8년 까지 default로 사용해 왔었다.
  • 배열로 된 Slab object 큐가 CPU와 노드에서 사용된다.
  • 메타 데이터 조각이 앞쪽에 배치되어 오브젝트의 정렬이 어려워 메모리 부족으로 캐시를 클리닝하는 경우 매우 복잡한 처리가 필요하다.
  • 처음 생성된 slab은 full 배열에서 관리되다가 object가 하나라도 사용되는 경우 그 slab은 partial 배열로 이동되어 관리된다. 다 사용하는 경우 다시 이동되어 empty 배열에서 관리된다.
  • slab은 노드 slab 및 cpu slab으로도 각각 관리된다.

 

Slub

  • 2007~8년 부터 PC 리눅스나 메모리가 충분히 있는 임베디드 시스템에서 default로 사용한다.
  • Slab과 다르게 메모리 오버헤드를 줄이기 위해  Slab object 큐 대신 단순히 한 페이지의 slub page를 큐로 사용한다.
  • Slab과 다르게 메타 정보를 별도로 사용하지 않고 이미 존재하는 page 구조체 배열로 구성된 메모리맵(mem_map)을 이용한다.
    • void *freelist;
      • 첫 번째 free object를 가리킨다.
    • short unsigned int inuse;
      • slab으로 할당된 object의 갯수 (사용중인 object 갯수)
      • 처음에 slab이 생성된 시점에 갯수는 0이다.
    • short unsigned int offset;
      • 다음 object를 찾기 위해 사용된다.
    • page 구조체내의 flags에서 PG_slab  비트를 설정하여 이 페이지를 slub으로 사용하는 것을 알린다.
    • page 구조체에 여러 필드를 추가하면 사이즈가 커지므로 union을 사용하여 사이즈를 절약하였다.
    • slub을 위해 page 구조체에 다음과 같이 3개의 멤버가 추가되었다.
  • workqueue의 특별한 스레드는 cpu slub을 감시하다 cpu당 할당된 slub이 사용되지 않는 경우 다른 cpu가 사용할 수 있도록 partial list에 되돌려 놓는다.
  • slub과 다르게 처음 생성된 slab은 inuse가 0으로 시작하여, object가 하나라도 사용되는 경우 그 slub은 partial 리스트로 관리된다. 만일 object가 다 사용되는 경우 slub은 partial 리스트에서 제거되고 관리 매커니즘에서 제외된다. 그러나 그 slub이 하나의 object라도 free 되는 경우 다시 partial 리스트에 추가되어 관리된다.
  • slub 역시 slab과 동일하게 노드 slab 및 cpu slab으로도 각각 관리된다.
  • slab에 비해 slub을 사용하면서 시스템 내의 slab 캐시가 줄었고(50% 정도), slab 할당자의 지역성(locality)이 향샹되었으며, slab 메모리의 단편화가 줄어들었다.
  • free object들은 offset를 0으로 하여 object의 가장 선두에 FP(Free Pointer)를 사용해 다음 free object의 주소를 가리키고 있다. 다만 SLAB_DESTROY_BY_RCU 및 SLAB_POISON 플래그 옵션을 사용하였거나 생성자를 사용한 경우 offset에 object_size를 대입하여 FP(Free Pointer)를 object_size 만큼 뒤로 이동시킨다.

 

Slob

  • low memory footprint를 갖는 임베디드 리눅스에서 선택하여 사용한다.
  • 속도는 가장 느리지만 메모리 소모가 가장 적다.

 

Slub object의 구조

Slub object는 커널이 사용하는 정규 메모리 할당의 최소 단위이다.

FP(Free Pointer)
  • 페이지 프레임 내에 존재하는 각 object들이 free 상태일 때 object의 선두에 있는 FP(Free Pointer)를 통해 다음 free object를 가리키게한다. object를 디버깅하는 경우 object를 사용하지 않아도 object의 모든 데이터가 uninitialized poison 데이터로 설정되고 이를 모니터하여 혹시 침해를 입지 않는지 확인하는데 사용한다. 따라서 이러한 경우에는 FP(Free Pointer)를 object의 뒤로 이동시켜 사용한다. 그 다음에 owner track 필드와 red zone 필드가 추가되어 디버깅에 사용된다.

 

다음 그림은 메타 정보 유무에 따른 Slub object의 구조이다.

a) 메타 정보 없는 slub object

  • size는 8 바이트부터 시작하여 포인터 길이 단위로 align된다.
  • SLAB_HWCACHE_ALIGN GPF 플래그를 사용 시 L1 캐시 라인 사이즈보다 작은 경우 캐시 라인 바운싱을 최소화 시키기 위해 align 단위를 2의 차수  단위로 줄인 수에 맞게 사용한다.
    • 예: …, 64, 32, 16, 8
  • 다음 free object를 가리키는 FP(Free Pointer)는 선두에 있다.
    • offset=0

 

  1. object가 이미 align된 경우 포인터 길이만큼 추가 (red zone=1~포인터길이 바이트)
  2. 워드 패딩을 추가한 길이를 s→align 단위로 정렬

 

b) 메타 정보 있는 slub object

  1. 워드 단위로 align
  2. FP(Freelist Pointer)가 offset 만큼 이동한다.
  3. SLAB_STORE_USER GFP 플래그 사용 시 track 구조체 x 2 길이만큼 추가
  4. s→align 단위로 정렬

  1. object가 이미 align된 경우 포인터 길이만큼 추가 (red zone=1~포인터길이 바이트)
  2. FP(Freelist Pointer)가 offset 만큼 이동한다.
  3. SLAB_STORE_USER GFP 플래그 사용 시 track 구조체 x 2 길이만큼 추가
  4. 워드 패딩을 추가한 길이를 s→align 단위로 정렬

 

구조체

kmem_cache 구조체 (slub)

include/linux/slub_def.h

/*
 * Slab cache management.
 */
struct kmem_cache {
        struct kmem_cache_cpu __percpu *cpu_slab;
        /* Used for retriving partial slabs etc */
        unsigned long flags;
        unsigned long min_partial;
        int size;               /* The size of an object including meta data */
        int object_size;        /* The size of an object without meta data */
        int offset;             /* Free pointer offset. */
        int cpu_partial;        /* Number of per cpu partial objects to keep around */
        struct kmem_cache_order_objects oo;

        /* Allocation and freeing of slabs */
        struct kmem_cache_order_objects max;
        struct kmem_cache_order_objects min;
        gfp_t allocflags;       /* gfp flags to use on each alloc */
        int refcount;           /* Refcount for slab cache destroy */
        void (*ctor)(void *);
        int inuse;              /* Offset to metadata */
        int align;              /* Alignment */
        int reserved;           /* Reserved bytes at the end of slabs */
        const char *name;       /* Name (only for display!) */
        struct list_head list;  /* List of slab caches */
#ifdef CONFIG_SYSFS
        struct kobject kobj;    /* For sysfs */
#endif
#ifdef CONFIG_MEMCG_KMEM
        struct memcg_cache_params memcg_params;
        int max_attr_size; /* for propagation, maximum size of a stored attr */
#ifdef CONFIG_SYSFS
        struct kset *memcg_kset;
#endif
#endif

#ifdef CONFIG_NUMA
        /*
         * Defragmentation by allocating from a remote node.
         */
        int remote_node_defrag_ratio;
#endif
        struct kmem_cache_node *node[MAX_NUMNODES];
};
  • cpu_slab
    • per cpu 캐시
  • flags
    • 캐시 생성 시 적용된 플래그 옵션
  • min_partial
    • 캐시에서 유지할 최소 partial slab(slub) 페이지 수
  • size
    • 메타 데이터를 포함한 object의 사이즈
  • object_size
    • 메타 데이터를 제외한 object의 사이즈 (원 요청 사이즈)
  • offset
    • FP(Free Pointer) 오프셋
      • SLAB_POISON 및 SLAB_DESTROY_BY_RCU를 사용하지 않는 경우 0
  • cpu_partial
    • per cpu 캐시에서 유지할 partial 리스트의 최대 slab(slub) object 수
  • oo
    • slab(slub) 페이지 생성 시 적용할 권장 order
  •  min
    • slab(slub) 페이지 생성 시 최소 order
  • max
    • slab(slub) 페이지 생성 시 최대 order
  • allocflags
    • object 할당 시 사용할 GFP 플래그
  • refcount
    • 캐시를 삭제하기 위해 사용할 레퍼런스 카운터(alias 캐시 생성 시 계속 증가)
  • *ctor
    • object 생성자
  • inuse
    • 메타 데이터의 offset
      • 메타 데이터(SLAB_POISON, SLAB_DESTROY_BY_RCU, SLAB_STORE_USER)를 사용하지 않는 경우 offset=0
  • align
    • 정렬할 바이트 수
  • reserved
    • slub object의 끝에 reserve 시켜야 할 바이트 수
  • *name
    • 출력을 위한 이름
  • list
    • 캐시들을 연결하기 위한 리스트 엔트리
  • kobj
    • sysfs에 사용할 디렉토리
  • memcg_param
    • 메모리 cgroup에서 사용하는 파라메터
  • max_attr_size
    • 속성이 저장될 최대 사이즈
  • *memcg_kset
    • 메모리 cgroup에서 사용하는 kset
  • remote_node_defrag_ratio
    • 할당할 slub object가 로컬노드의 partial 리스트에서 부족한 경우 리모트 노드의 partail 리스트에서 시도할 확률
    • 0~1023 (100=로컬노드의 partial 리스트에서 slub object를 할당할 수 없을 때 약 10%의 확률로 리모트 노드에서 시도)
  • *node
    • 노드별 partial 리스트를 관리하는 kmem_cache_node 배열 포인터

 

kmem_cache_cpu 구조체 (slub)

include/linux/slub_def.h

struct kmem_cache_cpu {
        void **freelist;        /* Pointer to next available object */
        unsigned long tid;      /* Globally unique transaction id */
        struct page *page;      /* The slab from which we are allocating */
        struct page *partial;   /* Partially allocated frozen slabs */
#ifdef CONFIG_SLUB_STATS
        unsigned stat[NR_SLUB_STAT_ITEMS];
#endif
};
  • **freelist
    • 할당할 free object 리스트
  • tid
    • 글로벌하게 유니크한 트랜잭션 id
  • *page
    • slub 페이지
  • *partial
    • 일부가 사용(in-use)된 frozen된 slub 페이지
  • stat
    • slub에 관련된 통계

 

kmem_cache_node 구조체 (slab, slub)

mm/slab.h

#ifndef CONFIG_SLOB
/*      
 * The slab lists for all objects.
 */     
struct kmem_cache_node {
        spinlock_t list_lock;

#ifdef CONFIG_SLAB
        struct list_head slabs_partial; /* partial list first, better asm code */       
        struct list_head slabs_full;
        struct list_head slabs_free;
        unsigned long free_objects;
        unsigned int free_limit;
        unsigned int colour_next;       /* Per-node cache coloring */
        struct array_cache *shared;     /* shared per node */
        struct alien_cache **alien;     /* on other nodes */
        unsigned long next_reap;        /* updated without locking */
        int free_touched;               /* updated without locking */
#endif  
        
#ifdef CONFIG_SLUB
        unsigned long nr_partial;
        struct list_head partial;
#ifdef CONFIG_SLUB_DEBUG
        atomic_long_t nr_slabs;
        atomic_long_t total_objects;
        struct list_head full;
#endif
#endif 

};
#endif
  • list_lock
    • spin lock에서 사용
  • nr_partial
    • 유지할 partial 리스트의 수
  • partial
    • partial된 slab(slub) 페이지가 연결될 리스트 헤드
      • slab과 다르게 slub은 partial 상태를 구별하지 않는다.
  • nr_slabs
    • slab(slub) 페이지 수
  • total_objects
    • object의 총 갯수
  • full
    • 다 사용된(in-use) slub 페이지가 연결될 리스트 헤드

 

slub으로 사용되는 주요 page 구조체 멤버

  • counters
    • objects, inuse, frozen을 담고 있다.
  • objects
    • counters[31:16]과 동일하며 object의 총 갯수
  • inuse
    • counters[15:1]과 동일하며 사용중인 object의 총 갯수
  • frozen
    • counters[0]과 동일하며 frozen 여부
  • freelist
    • free object 리스트
  • lru
    • per cpu 캐시 또는 per 노드의 partial 리스트에 연결되는 리스트 엔트리로 사용

 

kmem_cache_order_objects 구조체

include/linux/slub_def.h

/*
 * Word size structure that can be atomically updated or read and that
 * contains both the order and the number of objects that a slab of the
 * given order would contain.
 */
struct kmem_cache_order_objects {
        unsigned long x;
};
  • x[15:0]
    • slub 페이지를 만들 때 사용할 최대 object 수
  •  x[31:16]
    • slub 페이지를 만들 때 사용할 order

 

참고

 

 

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.