内核版本: 2.6.11
1. 高速缓存类型
高速缓存分为两种类型:普通和专用。
普通高速缓存由slab分配器用于自己的目的,而专用缓存则有内核其他部分创建使用。
专用高速缓存由kmem_cache_create()函数创建,创建一个专用高速缓存,这个缓存中object大小是固定的。
2. 使用场景
专用高速缓存:频繁使用固定大小内存,创建一个指定大小的cache,然后在这个cache中申请和释放object。
普通高速缓存:偶尔使用某个大小的object,单独创建个cache则显得浪费,内核提供了普通高速缓存。
3. 普通高速缓存实现
3.1 malloc_sizes
506 /* These are the default caches for kmalloc. Custom caches can have other sizes. */
507 struct cache_sizes malloc_sizes[] = {
508 #define CACHE(x) { .cs_size = (x) },
509 #include <linux/kmalloc_sizes.h>
510 { 0, }
511 #undef CACHE
512 };
这个数组包含了一系列通用大小的cache,大小为2^5, 2^6…33554432大小obj的缓存。
malloc_sizes包含一个头文件kmalloc_sizes.h,内容如下:
1 #if (PAGE_SIZE == 4096)
2 CACHE(32)
3 #endif
4 CACHE(64)
5 #if L1_CACHE_BYTES < 64
6 CACHE(96)
7 #endif
8 CACHE(128)
9 #if L1_CACHE_BYTES < 128
10 CACHE(192)
11 #endif
12 CACHE(256)
13 CACHE(512)
14 CACHE(1024)
15 CACHE(2048)
16 CACHE(4096)
17 CACHE(8192)
18 CACHE(16384)
19 CACHE(32768)
20 CACHE(65536)
21 CACHE(131072)
22 #ifndef CONFIG_MMU
23 CACHE(262144)
24 CACHE(524288)
25 CACHE(1048576)
26 #ifdef CONFIG_LARGE_ALLOCS
27 CACHE(2097152)
28 CACHE(4194304)
29 CACHE(8388608)
30 CACHE(16777216)
31 CACHE(33554432)
32 #endif /* CONFIG_LARGE_ALLOCS */
33 #endif /* CONFIG_MMU */
结构体cache_sizes定义如下:
76 /* Size description struct for general caches. */
77 struct cache_sizes {
78 size_t cs_size;
79 kmem_cache_t *cs_cachep;
80 kmem_cache_t *cs_dmacachep;
81 };
说明:
cs_size 指定了这一项中cache的object大小。每一项都包含两个cache,一个提供用于DMA操作的内存,一个提供用于正常操作的内存。
3.2 创建malloc_sizes指定cache
普通缓存的创建在kmem_cache_init中完成。
744 void __init kmem_cache_init(void)
745 {
746 size_t left_over;
747 struct cache_sizes *sizes;
748 struct cache_names *names;
...
793 /* 2+3) create the kmalloc caches */
794 sizes = malloc_sizes;
795 names = cache_names;
796
797 while (sizes->cs_size) {
798 /* For performance, all the general caches are L1 aligned.
799 * This should be particularly beneficial on SMP boxes, as it
800 * eliminates "false sharing".
801 * Note for systems short on memory removing the alignment will
802 * allow tighter packing of the smaller caches. */
803 sizes->cs_cachep = kmem_cache_create(names->name,
804 sizes->cs_size, ARCH_KMALLOC_MINALIGN,
805 (ARCH_KMALLOC_FLAGS | SLAB_PANIC), NULL, NULL);
806
807 /* Inc off-slab bufctl limit until the ceiling is hit. */
808 if (!(OFF_SLAB(sizes->cs_cachep))) {
809 offslab_limit = sizes->cs_size-sizeof(struct slab);
810 offslab_limit /= sizeof(kmem_bufctl_t);
811 }
812
813 sizes->cs_dmacachep = kmem_cache_create(names->name_dma,
814 sizes->cs_size, ARCH_KMALLOC_MINALIGN,
815 (ARCH_KMALLOC_FLAGS | SLAB_CACHE_DMA | SLAB_PANIC),
816 NULL, NULL);
817
818 sizes++;
819 names++;
820 }
......
在794到820行通过函数kmem_cache_create创建,大小为32,64,…,33554432大小的cache。
普通缓存,也是通过kmem_cache_create创建。
普通缓存的API
普通缓存kmalloc的定义如下:
85 static inline void *kmalloc(size_t size, int flags)
86 {
87 if (__builtin_constant_p(size)) {
88 int i = 0;
89 #define CACHE(x) \
90 if (size <= x) \
91 goto found; \
92 else \
93 i++;
94 #include "kmalloc_sizes.h"
95 #undef CACHE
96 {
97 extern void __you_cannot_kmalloc_that_much(void);
98 __you_cannot_kmalloc_that_much();
99 }
100 found:
101 return kmem_cache_alloc((flags & GFP_DMA) ?
102 malloc_sizes[i].cs_dmacachep :
103 malloc_sizes[i].cs_cachep, flags);
104 }
105 return __kmalloc(size, flags);
106 }
在87行中,如果是常量进入这个函数,重新定义CACHE(x),在kmalloc_size.h,有CACHE(32),CACHE(64),…,CACHE(33554432),分别执行90-93行,找到后,到found这个tag中,然后通过kmem_cache_alloc从之前创建的general cache中创建了object,并返回这个object。
如果不是常量,进入105行。
函数__kmalloc的定义如下:
2454 void * __kmalloc (size_t size, int flags)
2455 {
2456 struct cache_sizes *csizep = malloc_sizes;
2457
2458 for (; csizep->cs_size; csizep++) {
2459 if (size > csizep->cs_size)
2460 continue;
2461 #if DEBUG
2462 /* This happens if someone tries to call
2463 * kmem_cache_create(), or kmalloc(), before
2464 * the generic caches are initialized.
2465 */
2466 BUG_ON(csizep->cs_cachep == NULL);
2467 #endif
2468 return __cache_alloc(flags & GFP_DMA ?
2469 csizep->cs_dmacachep : csizep->cs_cachep, flags);
2470 }
2471 return NULL;
2472 }
找到和需要分配的size最接近的缓存,进入 函数 __cache_alloc从这个缓存( csizep->cs_cachep或者csizep->cs_dmacachep)分配到object。
2135 static inline void * __cache_alloc (kmem_cache_t *cachep, int flags)
2136 {
2137 unsigned long save_flags;
2138 void* objp;
2139 struct array_cache *ac;
2140
2141 cache_alloc_debugcheck_before(cachep, flags);
2142
2143 local_irq_save(save_flags);
2144 ac = ac_data(cachep);
2145 if (likely(ac->avail)) {
2146 STATS_INC_ALLOCHIT(cachep);
2147 ac->touched = 1;
2148 objp = ac_entry(ac)[--ac->avail];
2149 } else {
2150 STATS_INC_ALLOCMISS(cachep);
2151 objp = cache_alloc_refill(cachep, flags);
2152 }
2153 local_irq_restore(save_flags);
2154 objp = cache_alloc_debugcheck_after(cachep, flags, objp, __builtin_return_address(0));
// 分配后调试检查
2155 return objp;
2156 }
通过cache_alloc_debugcheck_after从缓存cachep分配到object
参考
深入理解linux内核
Kernel那些事儿之内存管理(9) — Slab(下)