vmalloc,kmalloc,get_free_page,kmem_cache_create分配内存实例

本文深入探讨了Linux内核中的内存管理技术,包括vmalloc、kmalloc等内存分配函数的使用及区别,阐述了如何通过这些函数进行高效内存管理。

//All right revsered by yoki2009
//mailto:imj040144@tom.com
////微出版 www.epube.biz 相信梦想无界


#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/jiffies.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>

/*
vmalloc,kmalloc,get_free_page,kmem_cache_create
vmalloc与kmalloc区别在于起始地址不同,kmalloc分配的内存处于3GB~high_memory之间,这段内核
空间与物理内存的映射一一对应,而vmalloc分配的内存在VMALLOCSTAERT~4GB之间,这段非连续内存
区映射到物理内存也可能是非连续的,vmalloc分配的物理地址无需连续,而kmalloc确保页在物理上
是连续的

*/
unsigned char * vmchar;
unsigned char * kmchar;
unsigned char * m_free_pages;
struct kmem_cache_t  * kmem_cache;
unsigned char * slabchar;
static int __init mem_test_init(void)
{
 printk("Hello, world/n");
 //vmalloc test
 //分配虚拟内存,也就是位于高端128M内存
 printk("[vmalloc] Enter Jiffy %ld/n",jiffies);
 vmchar = (unsigned char *)vmalloc(16*1024*1024);
 if (!vmchar)
 {
  printk("Error on vmalloc/n");
  return -1;
 }
 memset(vmchar,0,16*1024*1024);
 printk("vmalloc address : %x/n",vmchar);

 //kmalloc test
 //kmalloc分配的低端内存,直接映射到物理内存
 printk("[kmalloc] Enter Jiffy %ld/n",jiffies);
 //kmalloc最大只能开辟128k
 kmchar = (unsigned char *)kmalloc(PAGE_SIZE*32,GFP_KERNEL);
 if (!kmchar)
 {
  printk("Error on kmalloc/n");
  return -1;
 }
 memset(kmchar,0,PAGE_SIZE*32);
 printk("kmalloc address : %x/n",kmchar);
 printk("[kmalloc] Exit Jiffy %ld/n",jiffies);
 
 //get_free_page test
 //也是使用kmalloc分配的内存区域
 printk("[get_free_pages] Enter Jiffy %ld/n",jiffies);
 m_free_pages = (unsigned char *)__get_free_pages(GFP_KERNEL,2);
 if (!m_free_pages)
 {
  printk("Error on m_free_pages/n");
  return -1;
 }
 memset(m_free_pages,'a',PAGE_SIZE*2);
/*
 while(m_free_pages)
 {
  printk("[get_free_pages] address == %x/n",m_free_pages>>PAGE_SHIFT);
 }
*/
 printk("get_free_pages address : %x/n",m_free_pages);
 printk("[get_free_pages] Exit Jiffy %ld/n",jiffies);

 //slab alloc test
 //使用后备高速缓存,对于反复地分配很多同一大小的内存块使用Slab分配方式
 printk("[Slab] Enter Jiffy %ld/n",jiffies);
 kmem_cache = kmem_cache_create("slab_cache",4,0,SLAB_HWCACHE_ALIGN,NULL);
 if (!kmem_cache)
 {
  printk("Error on Slab/n");
  return -1;
 }
 slabchar = kmem_cache_alloc(kmem_cache,GFP_KERNEL);
 if (!slabchar)
 {
  printk("Error on alloc slab cache/n");
  return -1;
 }
 memset(slabchar,0,4);
 printk("Slab address : %x/n",slabchar);
 kmem_cache_free(kmem_cache,slabchar);
 kmem_cache_destroy(kmem_cache);
 printk("[Slab] Exit Jiffy %ld/n",jiffies);
 return 0;
}

static void __exit mem_test_exit(void)
{
 vfree(vmchar);
 kfree(kmchar);
 free_pages(m_free_pages,2);
}

module_init(mem_test_init);

module_exit(mem_test_exit);

### Linux 内核内存分配机制:kmallocvmalloc 和 _get_free_pages 的区别 #### 1. kmalloc `kmalloc` 是 Linux 内核中用于分配连续物理地址和逻辑地址的内存分配函数。其核心实现基于 SLAB/SLUB/SLOB 分配器,能够高效地管理小型内存块的分配。 - 如果申请的大小小于或等于 `KMALLOC_MAX_CACHE_SIZE`,则通过 `kmem_cache_alloc_trace` 从预定义的缓存池中分配内存[^3]。 - 如果申请的大小超过 `KMALLOC_MAX_CACHE_SIZE`,则调用 `kmalloc_large`,该函数会通过 `__get_free_pages` 分配大块内存,并将其映射到连续的虚拟地址空间[^1]。 ```c static __always_inline void *kmalloc(size_t size, gfp_t flags) { if (__builtin_constant_p(size)) { if (size > KMALLOC_MAX_CACHE_SIZE) return kmalloc_large(size, flags); // 小型内存分配逻辑 } return __kmalloc(size, flags); } ``` #### 2. vmalloc `vmalloc` 用于分配逻辑地址连续但物理地址不连续的内存区域。它通过页表映射将分散的物理页面组合成一个连续的虚拟地址空间。 - `vmalloc` 分配的内存不会占用连续的物理内存,因此适合分配较大的内存块。 - 内核通过 `nr_vmalloc_pages` 记录所有通过 `vmalloc` 分配的内存大小,并在 `/proc/meminfo` 的 `VmallocUsed` 中显示这些统计信息[^2]。 ```c void *vmalloc(unsigned long size) { struct page **pages; unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; pages = alloc_vm_area(nr_pages * sizeof(struct page *)); if (!pages) return NULL; if (__vmalloc_area.pages == NULL) return NULL; return __vmalloc_area.addr; } ``` #### 3. _get_free_pages `_get_free_pages` 是一种低级内存分配接口,直接从伙伴系统(buddy system)中分配指定数量的连续物理页面。它返回的是逻辑地址连续的内存块。 - 使用 `gfp_t` 标志控制分配行为,例如是否允许睡眠、是否需要 DMA 兼容内存等。 - 分配的页面数量由 `order` 参数决定,`order = 0` 表示分配单个页面,`order = 1` 表示分配 2 个连续页面,依此类推。 ```c unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order) { struct page *page; page = alloc_pages(gfp_mask, order); if (!page) return 0; return (unsigned long) page_address(page); } ``` #### 比较与总结 | 特性 | kmalloc | vmalloc | _get_free_pages | |-------------------------|------------------------------------------|-----------------------------------------|-----------------------------------------| | **地址连续性** | 物理地址和逻辑地址均连续 | 仅逻辑地址连续 | 物理地址和逻辑地址均连续 | | **适用场景** | 小型内存分配 | 大型内存分配 | 中等规模内存分配 | | **分配效率** | 高效 | 较低(涉及页表操作) | 较高 | | **最大分配大小** | 受限于 `KMALLOC_MAX_CACHE_SIZE` | 理论上无限制 | 受限于可用连续物理内存 | | **实现方式** | 基于 SLAB/SLUB/SLOB 缓存池 | 基于页表映射 | 直接从伙伴系统分配 | #### 注意事项 - `kmalloc` 更适合分配小型内存块,而 `vmalloc` 则适合分配大型内存块。 - `_get_free_pages` 提供了更大的灵活性,但分配的内存块大小必须是 2 的幂次方。 - 在多核系统中,`vmalloc` 的性能可能受到页表更新的限制[^2]。 ### 示例代码 以下是一个简单的示例,展示如何使用 `kmalloc`、`vmalloc` 和 `_get_free_pages` 分配内存: ```c #include <linux/kernel.h> #include <linux/slab.h> #include <linux/vmalloc.h> void example_memory_allocation(void) { char *kmalloc_ptr, *vmalloc_ptr; unsigned long get_free_pages_ptr; // 使用 kmalloc 分配 128 字节内存 kmalloc_ptr = kmalloc(128, GFP_KERNEL); if (!kmalloc_ptr) pr_err("kmalloc failed\n"); // 使用 vmalloc 分配 4KB 内存 vmalloc_ptr = vmalloc(4096); if (!vmalloc_ptr) pr_err("vmalloc failed\n"); // 使用 _get_free_pages 分配 2 个连续页面(8KB) get_free_pages_ptr = __get_free_pages(GFP_KERNEL, 1); if (!get_free_pages_ptr) pr_err("_get_free_pages failed\n"); // 清理分配的内存 kfree(kmalloc_ptr); vfree(vmalloc_ptr); free_pages(get_free_pages_ptr, 1); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值