1. 总览
如下为内核开发或驱动开发常见的内存管理API关系,其他如CMA分配器等相关API未列出。
1.1. 框架图
1.2. 函数图总览
2. memblock分配器
memblock分配器主要用于Linux启动时的内存分配,被memblock_alloc分配后未被释放的内存,不会被加入到页管理器中。
| api | param | desc |
|---|---|---|
| memblock_alloc | size, align | size表示要申请的大小,align表示内存对齐大小 |
3. 页分配器
页分配器相关的函数或宏在include/linux/gfp.h中声明。常用的函数如下:
| return | api | param |
|---|---|---|
| unsigned long | __get_free_pages | gfp_mask, order |
| unsigned long | __get_free_page | gfp_mask |
| unsigned long | __get_dma_pages | gfp_mask, order |
| unsigned long | get_zeroed_page | gfp_mask |
| struct page * | alloc_page | gfp_mask |
| struct page * | alloc_pages | gfp_mask, order |
| void | free_page | addr |
| void | free_pages | addr, order |
| void | __free_page | struct page * |
| void | __free_pages | struct page *, order |
4. slab分区器
| api | |
|---|---|
| kmem_cache_create | |
| KMEM_CACHE | kmem_cache_create的封装 |
| kmem_cache_create_usercopy | |
| KMEM_CACHE_USERCOPY | kmem_cache_create_usercopy的封装 |
| kmem_cache_alloc | |
| kmem_cache_zalloc | |
| kmem_cache_free | |
| kmem_cache_destroy | |
| kmem_cache_shrink | Shrink a cache |
| kmem_cache_size |
5. kmalloc
kmalloc只能分配几个固定大小的内存,申请值不在这些固定值之内时,会按向上对齐的原则,分配最接近申请值的内存块。
kmalloc会根据申请的内存来决定来决定使用块分配器(slab/slub/slob)或页分配器进行内存分配。
| api | |
|---|---|
| kmalloc | 申请连续的物理内存 |
| kzmalloc | 申请连续的物理内存,并对申请的内存清零 |
| kcalloc | 为多个对象申请连续的物理内存,并对申请的内存清零,内部调用kmalloc_array |
| kmalloc_array | 为数组申请连续的物理内存 |
| krealloc | 重新分配内存 |
| kfree | 释放内存 |
| kfree_sensitive | 释放内存前,将要释放的内存区域清零 |
| ksize | 返回所分配的对象的实际内存的大小,不一定与kmalloc或kmem_cache_alloc传入值一致 |
| kstrdup | 根据给定字符串申请内存,并完成字符串拷贝 |
6. vmalloc
vmalloc原理是分配多个物理页面(不保证物理地址连续),然后将页面映射到连续的虚拟地址。所以vmalloc分配的粒度为页面大小,最终也会按页面大小进行对齐。
6.1. vmalloc
| api | |
|---|---|
| __vmalloc | 低级vmalloc函数,由其他api调用 |
| vmalloc | allocate virtually contiguous memory |
| vmalloc_node | allocate memory on a specific node |
| vmalloc_user | allocate zeroed virtually contiguous memory for userspace |
| vmalloc_huge | allocate virtually contiguous memory, allow huge pages |
| vmalloc_32 | allocate virtually contiguous memory (32bit addressable) |
| vmalloc_32_user | allocate zeroed virtually contiguous 32bit memory |
| vzalloc | allocate virtually contiguous memory with zero fill |
| vzalloc_node | allocate memory on a specific node with zero fill |
| vfree | |
| vfree_atomic | This one is just like vfree() but can be called in any atomic context except NMIs |
6.2. vmap
| api | |
|---|---|
| vmap | map an array of pages into virtually contiguous space |
| vmap_pfn | map an array of PFNs into virtually contiguous space |
| vunmap | |
| vm_map_ram | map pages linearly into kernel virtual address (vmalloc space) |
| vm_unmap_ram |
7. kvmalloc
逻辑上是,大于一页的时候用vmalloc(),小于等于1页用kmalloc()。
而kvmalloc()的实现代码里面则对类似逻辑进行了非常智能地处理。
大于一个page的时候,会先用kmalloc()进行__GFP_NORETRY的尝试,如果尝试失败就fallback到vmalloc(NORETRY标记避免了kmalloc在申请内存失败地情况下,反复尝试甚至做OOM来获得内存)。
当然,kvmalloc()的size如果小于1个page,则沿用kmalloc()逻辑,而且也不会设置__GFP_NORETRY,如果反复尝试失败的话,也不会fallback到vmalloc(),因为vmalloc()申请小于1个page的内存是不合适的。
| api | |
|---|---|
| kvmalloc | 根据申请内存大小自动决定使用kmalloc或vmalloc |
| kvzalloc | 内存申请成功后将其清零 |
| kvcalloc | 为多个对象申请内存,并将申请到的内存清零,内部调用kvmalloc_array |
| kvmalloc_array | 为数组申请内存 |
| kvfree | 释放申请到的内存 |
| kvfree_sensitive | 是否内存前对内存区域进行清零,与kvfree不同的是,kvfree_sensitive需要指定长度 |
| is_vmalloc_addr | 判断指针是否处于vmalloc区域 |
8. devm
devm的作用是自动释放申请的资源,无需再手动释放。
8.1. memory allocation
| api |
|---|
| devm_kmalloc |
| devm_kzalloc |
| devm_kcalloc |
| devm_krealloc |
| devm_kmalloc_array |
| devm_get_free_pages |
| devm_free_pages |
| devm_alloc_percpu |
| devm_free_percpu |
| devm_kasprintf |
| devm_kstrdup |
| devm_kstrdup_const |
| devm_kmemdup |
8.2. ioremap
| api | desc |
|---|---|
| devm_ioremap_resource | check, request region, and ioremap resource |
| devm_ioremap_resource_wc | write-combined variant of devm_ioremap_resource() |
| devm_of_iomap | Requests a resource and maps the memory mapped IO for a given device_node managed by a given device |