内存管理是内核最复杂同时也最重要的一部分。其特点在于非常需要处理器和内核之间的协
作。
内存管理的实现涵盖了许多领域;
就我们所知;Linux内核一般将处理器的虚拟地址空间划分为两个部分。底部比较大的部分用于用户进程;顶部则专用于内核。虽然;在两个用户进程之间的;上下文切换期间会改变下半部分;但虚拟地址空间的内核部分总是保持不变。地址空间在用户进程和内核之间划分的典型比例为3∶1。如;给出4 GB虚拟地址空间;3 GB将用于用户空间而1 GB将用于内核。
用户空间5中不同的内存段;
一个page大小为什么是4KB?
代码跟进;kernel/msm-5.4/arch/arm/include/asm/page.h
PAGE_SHIFT=12
如上图所示;可以计算: 2^ 12 = 4096 即4KB
有些同学可能会疑惑;为啥是KB不是kb?
^_^; 因为一个内存地址所代表的永远是1个字节即Byte 并非Bit
TODO
malloc是C标准提供的内存分配函数。
TODO
/** * kzalloc - allocate memory. The memory is set to zero. * ;size: how many bytes of memory are required. * ;flags: the type of memory to allocate (see kmalloc). */ static inline void *kzalloc(size_t size, gfp_t flags) { return kmalloc(size, flags | __GFP_ZERO); }
如上code可以看出;kzalloc() 函数与 kmalloc() 非常相似;参数及返回值是一样的;可以说是前者是后者的一个变种;因为 kzalloc() 实际上只是额外附加了 __GFP_ZERO 标志。所以它除了申请内核内存外;还会对申请到的内存内容清零。
vmalloc 是三个接口中唯一一个无法保证申请连续内存的接口;如果申请的内存size大于一个page size 即4KB;则无法确保申请到连续内存。
- GFP_ATOMIC —— 分配内存的过程是一个原子过程;分配内存的过程不会被;高优先级进程或中断;打断;无法休眠;
- GFP_KERNEL —— 正常分配内存;可以休眠;不能再中断上下文中使用;但是可以在进程上下文中使用。
- GFP_DMA —— 给 DMA 控制器分配内存;需要使用该标志;DMA要求分配虚拟地址和物理地址连续;。
如下代码分析;
kernel/msm-5.4/include/linux/slab.h
-> static __always_inline void *kmalloc(size_t size, gfp_t flags)
->void *__kmalloc(size_t size, gfp_t flags)
void *__kmalloc(size_t size, gfp_t flags) { struct kmem_cache *s; void *ret; if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) return kmalloc_large(size, flags); s = kmalloc_slab(size, flags); if (unlikely(ZERO_OR_NULL_PTR(s))) return s; ret = slab_alloc(s, flags, _RET_IP_); trace_kmalloc(_RET_IP_, ret, size, s->size, flags); ret = kasan_kmalloc(s, ret, size, flags); return ret; } EXPORT_SYMBOL(__kmalloc);
static __always_inline void *kmalloc_large(size_t size, gfp_t flags) { unsigned int order = get_order(size); return kmalloc_order_trace(size, flags, order); }
最大size 为;KMALLOC_MAX_CACHE_SIZE
申请的内存size 大于 KMALLOC_MAX_CACHE_SIZE则输出trace。
KMALLOC_MAX_CACHE_SIZE 定义在;kernel/msm-5.4/include/linux/slab.h
/* * Kmalloc array related definitions */ #ifdef CONFIG_SLAB /* * The largest kmalloc size supported by the SLAB allocators is * 32 megabyte (2^25) or the maximum allocatable page order if that is * less than 32 MB. * * WARNING: Its not easy to increase this value since the allocators have * to do various tricks to work around compiler limitations in order to * ensure proper constant folding. */ #define KMALLOC_SHIFT_HIGH ((MAX_ORDER ; PAGE_SHIFT - 1) <= 25 ? (MAX_ORDER ; PAGE_SHIFT - 1) : 25) #define KMALLOC_SHIFT_MAX KMALLOC_SHIFT_HIGH #ifndef KMALLOC_SHIFT_LOW #define KMALLOC_SHIFT_LOW 5 #endif #endif #ifdef CONFIG_SLUB /* * SLUB directly allocates requests fitting in to an order-1 page * (PAGE_SIZE*2). Larger requests are passed to the page allocator. */ #define KMALLOC_SHIFT_HIGH (PAGE_SHIFT ; 1) #define KMALLOC_SHIFT_MAX (MAX_ORDER ; PAGE_SHIFT - 1) #ifndef KMALLOC_SHIFT_LOW #define KMALLOC_SHIFT_LOW 3 #endif #endif #ifdef CONFIG_SLOB /* * SLOB passes all requests larger than one page to the page allocator. * No kmalloc array is necessary since objects of different sizes can * be allocated from the same page. */ #define KMALLOC_SHIFT_HIGH PAGE_SHIFT #define KMALLOC_SHIFT_MAX (MAX_ORDER ; PAGE_SHIFT - 1) #ifndef KMALLOC_SHIFT_LOW #define KMALLOC_SHIFT_LOW 3 #endif #endif /* Maximum allocatable size */ #define KMALLOC_MAX_SIZE (1UL << KMALLOC_SHIFT_MAX) /* Maximum size for which we actually use a slab cache */ #define KMALLOC_MAX_CACHE_SIZE (1UL << KMALLOC_SHIFT_HIGH) /* Maximum order allocatable via the slab allocagtor */ #define KMALLOC_MAX_ORDER (KMALLOC_SHIFT_MAX - PAGE_SHIFT)
可以查看内核.config配置来确认KMALLOC_SHIFT_HIGH;KMALLOC_SHIFT_MAX以及 KMALLOC_SHIFT_LOW。
如下所示;CONFIG_SLUB=y
CONFIG_VM_EVENT_COUNTERS=y # CONFIG_VM_EVENT_COUNT_CLEAN_PAGE_RECLAIM is not set CONFIG_SLUB_DEBUG=y # CONFIG_SLUB_MEMCG_SYSFS_ON is not set # CONFIG_COMPAT_BRK is not set # CONFIG_SLAB is not set CONFIG_SLUB=y # CONFIG_SLOB is not set # CONFIG_SLAB_MERGE_DEFAULT is not set CONFIG_SLAB_FREELIST_RANDOM=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_SHUFFLE_PAGE_ALLOCATOR=y CONFIG_SLUB_CPU_PARTIAL=y CONFIG_SYSTEM_DATA_VERIFICATION=y CONFIG_PROFILING=y CONFIG_TRACEPOINTS=y # end of General setup
CONFIG_FORCE_MAX_ZONEORDER=11
CONFIG_QTI_QUIN_GVM=y CONFIG_FORCE_MAX_ZONEORDER=11 CONFIG_UNMAP_KERNEL_AT_EL0=y CONFIG_HARDEN_BRANCH_PREDICTOR=y
那么 KMALLOC_SHIFT_MAX = (MAX_ORDER ; PAGE_SHIFT - 1) 即 11;12-1 = 22;
#define KMALLOC_MAX_SIZE (1UL << KMALLOC_SHIFT_MAX)
可以算出;KMALLOC_MAX_SIZE 为 2^22 = 4,194,304
4,194,304/1024 = 4096KB
4096KB/1024 = 4MB
所以;采用kzalloc 、kmalloc分配内存;最大为4MB。