有了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中。
转载于:https://blog.51cto.com/richardguo/1678760