有了Slab的数据结构和操作方法之后,就可以创建一个指定大小的cache,然后在这个cache中申请和释放object。这个做法很适合这种应用场景:频繁地使用一固定大小的内存空间。
如果只是偶尔使用某个大小的内存空间,为此新建一个cache就有点得不偿失。针对于这种应用场景,内核提供了一系列 general caches。今天我们就来看一看这些general caches是怎么工作的。
其思想很简单:这些general caches会在系统初始化时提前创建好,且其大小按照2的幂次方由小到大分布,即 2^5, 2^6, ..., 2^25,其上限由 KMALLOC_MAX_SIZE 决定。当申请某一大小 size 的内存空间时,只需找出比size大的最小的general cache,然后从中分配object就可以了。这样可以保证内碎片总是小于50%。
1. malloc_sizes
那这些已经创建好的general caches放在哪里了呢?它们放在了数组 malloc_sizes 中。
640 struct cache_sizes malloc_sizes[] = { 641 #define CACHE(x) { .cs_size = (x) }, 642 #include <linux/kmalloc_sizes.h> 643 CACHE(ULONG_MAX) 644 #undef CACHE 645 };
这个数组不大容易看清楚。我们一点点来。
首先,该数组中成员变量的类型是 struct cache_sizes。
19 struct cache_sizes { 20 size_t cs_size; 21 struct kmem_cache *cs_cachep; 22 #ifdef CONFIG_ZONE_DMA 23 struct kmem_cache *cs_dmacachep; 24 #endif 25 };
cs_size 指定了这一项中cache的object大小。每一项都包含两个cache,一个提供用于DMA操作的内存,一个提供用于正常操作的内存。
其次,数组 malloc_sizes 中包含了一个头文件,这个头文件就定义了该数组都有哪些 size 的general cache。该头文件内容为:
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 #if KMALLOC_MAX_SIZE >= 262144 23 CACHE(262144) 24 #endif 25 #if KMALLOC_MAX_SIZE >= 524288 26 CACHE(524288) 27 #endif 28 #if KMALLOC_MAX_SIZE >= 1048576 29 CACHE(1048576) 30 #endif 31 #if KMALLOC_MAX_SIZE >= 2097152 32 CACHE(2097152) 33 #endif 34 #if KMALLOC_MAX_SIZE >= 4194304 35 CACHE(4194304) 36 #endif 37 #if KMALLOC_MAX_SIZE >= 8388608 38 CACHE(8388608) 39 #endif 40 #if KMALLOC_MAX_SIZE >= 16777216 41 CACHE(16777216) 42 #endif 43 #if KMALLOC_MAX_SIZE >= 33554432 44 CACHE(33554432) 45 #endif
最后,数组 malloc_sizes 的最后定义了一个大小为 ULONG_MAX 的general cache。这个cache在系统初始化的时候不会被创建,而是赋值为NULL。这样,如果有人申请了大于头文件 kmalloc_sizes.h 中定义的最大长度的内存时,就会得到NULL。
2. kmalloc/kfree
这些general caches对外提供的API就是kmalloc和kfree。
31 static inline void *kmalloc(size_t size, gfp_t flags) 32 { 33 if (__builtin_constant_p(size)) { 34 int i = 0; 35 36 if (!size) 37 return ZERO_SIZE_PTR; 38 39 #define CACHE(x) 40 if (size <= x) 41 goto found; 42 else 43 i++; 44 #include "kmalloc_sizes.h" 45 #undef CACHE 46 { 47 extern void __you_cannot_kmalloc_that_much(void); 48 __you_cannot_kmalloc_that_much(); 49 } 50 found: 51 #ifdef CONFIG_ZONE_DMA 52 if (flags & GFP_DMA) 53 return kmem_cache_alloc(malloc_sizes[i].cs_dmacachep, 54 flags); 55 #endif 56 return kmem_cache_alloc(malloc_sizes[i].cs_cachep, flags); 57 } 58 return __kmalloc(size, flags); 59 }
kmalloc首先看一下参数中的size是不是一个常量。这种情况下,要使用的general cache在编译阶段就可以确定了,这对性能很有好处。
如果size不是常量,会最终调用到函数 __do_kmalloc()。
3714 static __always_inline void *__do_kmalloc(size_t size, gfp_t flags, 3715 void *caller) 3716 { 3717 struct kmem_cache *cachep; 3724 cachep = __find_general_cachep(size, flags); 3725 if (unlikely(ZERO_OR_NULL_PTR(cachep))) 3726 return cachep; 3727 return __cache_alloc(cachep, flags, caller); 3728 }
该函数利用 __find_general_cachep() 找到合适的general cache,然后调用我们之前讲过的__cache_alloc()来从找到的cache中分配一个object出来。
765 static inline struct kmem_cache *__find_general_cachep(size_t size, 766 gfp_t gfpflags) 767 { 768 struct cache_sizes *csizep = malloc_sizes; 777 if (!size) 778 return ZERO_SIZE_PTR; 779 780 while (size > csizep->cs_size) 781 csizep++; 782 783 /* 784 * Really subtle: The last entry with cs->cs_size==ULONG_MAX 785 * has cs_{dma,}cachep==NULL. Thus no special case 786 * for large kmalloc calls required. 787 */ 788 #ifdef CONFIG_ZONE_DMA 789 if (unlikely(gfpflags & GFP_DMA)) 790 return csizep->cs_dmacachep; 791 #endif 792 return csizep->cs_cachep; 793 }
该函数根据size来找出合适的general cache。
780 ~ 781意思很明显,要找到比size大的最小的general cache。
3780 void kfree(const void *objp) 3781 { 3782 struct kmem_cache *c; 3783 unsigned long flags; 3784 3785 if (unlikely(ZERO_OR_NULL_PTR(objp))) 3786 return; 3787 local_irq_save(flags); 3788 kfree_debugcheck(objp); 3789 c = virt_to_cache(objp); 3790 debug_check_no_locks_freed(objp, obj_size(c)); 3791 __cache_free(c, (void *)objp); 3792 local_irq_restore(flags); 3793 }
3789行根据object的地址,找出其对应的cache的地址。这一点并不难,因为cache的地址保存在了object所在页面的页描述符中的lru.next中了。
3791行调用我们之前讲过的__cache_free()来把object释放回前面找到的cache中。