メモリは Linux システムで最も重要なリソースの 1 つであり、データ、コード、スタックなどの保存に使用できます。メモリの適用と解放は、Linux ドライバ開発における最も基本的な操作の 1 つであり、カーネル空間とユーザー空間、静的割り当てと動的割り当て、連続メモリと不連続メモリなどの概念が含まれます。この記事では、kmalloc、vmalloc、get_free_pages、dma_alloc_coherent などの Linux ドライバーのメモリ アプリケーション テクノロジを紹介し、使用例と注意事項を説明します。
基本的なことから始めましょう。下の図は Linux のメモリ マッピング モデルです。
#「」
”
は主に、1 ページ サイズ未満のメモリ を適用するために使用されます。 kmalloc の最下層は **__get_free_pages を呼び出す必要があります。パラメータ内のメモリ タイプを示す gtp_t フラグは、この関数の略称です。一般的に使用されるメモリ タイプには、GFP_USER、GFP_KERNEL、GFP_ATOMIC** が含まれます。
もあります。 リーリー
はメモリを管理するため、常にページ単位でメモリを割り当てます** リーリー
同じシリーズの API には、もあります。
unsigned long __get_free_page(gfp_t gfp) unsigned long get_zeroed_page(gfp_t gfp_mask) struct page *alloc_pages(gfp_t gfp_mask, unsigned int order) void free_page(unsigned long addr)
vmalloc在虚拟内存空间给出一块连续的内存区,实质上,这片连续的虚拟内存在物理内存中并不一定连续,所以vmalloc申请的虚拟内存和物理内存之间也就没有简单的换算关系,正因如此,vmalloc()通常用于分配远大于__get_free_pages()的内存空间,它的实现需要建立新的页表,此外还会调用使用GFP_KERN的kmalloc,so,一定不要在中断处理函数,tasklet和内核定时器等非进程上下文中使用vmalloc!
/** * vmalloc - allocate virtually contiguous memory * @size: allocation size * Allocate enough pages to cover @size from the page level allocator and map them into contiguous kernel virtual space. */ void *vmalloc(unsigned long size) /** * vfree - release memory allocated by vmalloc() * @addr: memory base address */ void vfree(const void *addr)
同系列的API还有
/** * vmalloc_32 - allocate virtually contiguous memory (32bit addressable) * @size: allocation size * Allocate enough 32bit PA addressable pages to cover @size from the page level allocator and map them into contiguous kernel virtual space. */ void *vmalloc_32(unsigned long size)
我们知道,页是内存映射的基本单位,但内核中很多频繁创建的对象所需内存都不到一页,此时如果仍然按照页映射的方式,频繁的进行分配和释放就会造成资源的浪费,同时也会降低系统性能。为了解决的这样的问题,内核引入了slab机制,使对象在前后两次被使用时被分配在同一块内存或同一类内存空间,且保留了基本的数据结构,就可以大大提高效率。kmalloc的底层即是使用slab算法管理分配的内存的。注意,slab依然是以页为单位进行映射,只是映射之后分割这些页为相同的更小的单元,从而节省了内存。slab分配的单元不能小于32B或大于128K。
/** * kmem_cache_create - 创建slab缓存对象 * @name:slab缓存区名字, * @size:slab分配的缓存区的每一个单元的大小 * @align:缓存区内存的对齐方式,一般给0 * @flags:控制分配的位掩码, * %SLAB_POISON - Poison the slab with a known test pattern (a5a5a5a5) to catch references to uninitialised memory. * %SLAB_RED_ZONE - Insert `Red' zones around the allocated memory to check for buffer overruns. * %SLAB_HWCACHE_ALIGN - Align the objects in this cache to a hardware cacheline. This can be beneficial if you're counting cycles as closely as davem. * %SLAB_CACHE_DMA - Use GFP_DMA memory * %SLAB_STORE_USER - Store the last owner for bug hunting *define SLAB_PANIC - Panic if kmem_cache_create() fails */ struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align,unsigned long flags, void (*ctor)(void *)) /** * kmem_cache_alloc - Allocate an object from this cache. * @cachep: The cache to allocate from. * @flags: See kmalloc(). * The flags are only relevant if the cache has no available objects. */ void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags) /** * kmem_cache_free - Deallocate an object * @cachep: The cache the allocation was from. * @objp: The previously allocated object. * Free an object which was previously allocated from this cache. */ void kmem_cache_free(struct kmem_cache *cachep, void *objp) void kmem_cache_destroy(struct kmem_cache *s)
//创建slab对象 struct kmem_cache_t *xj_sbcache; xj_sbcache = kmem_cache_create("xjslab",sizeof(struct xj_unit_t),0,SLAB_CACHE_DMA|SLAB_PANIC,NULL,NULL); //分配slab缓存 struct xj_unit_t *xj_unit; xj_unit = kmem_cache_alloc(xj_sbcache,GFP_KERNEL); /* 使用slab缓存 */ /* 释放slab缓存 */ kmem_cache_free(xj_sbcache, xj_unit); /* 销毁slab缓存 */ kmem_cache_destroy(xj_sbcache);
除了slab机制,内核还提供了传统的内存池机制来管理小块内存的分配。内存池主要是用来解决可能出现的内存不足的情况,因为一个内存池在创建的时候就已经分配好了一内存,当我们用mempool_alloc向一个已经创建好的内存池申请申请内存时,该函数首先会尝试回调内存池创建时的分配内存函数,如果已经没有内存可以分配,他就会使用内存池创建时预先分配的内存,这样就可以避免因为无内存分配而陷入休眠,当然,如果预分配的内存也已经使用完毕,还是会陷入休眠。slab机制的目的是提高内存使用率以及内存管理效率,内存池的目的是避免内存的分配失败。下面是内核中提供的关于内存池的API
/** * mempool_create - create a memory pool * @min_nr: the minimum number of elements guaranteed to be allocated for this pool. * @alloc_fn: user-defined element-allocation function. * @free_fn: user-defined element-freeing function. * @pool_data: optional private data available to the user-defined functions. * * this function creates and allocates a guaranteed size, preallocated memory pool. The pool can be used from the mempool_alloc() and mempool_free() functions. * This function might sleep. Both the alloc_fn() and the free_fn() functions might sleep - as long as the mempool_alloc() function is not called from IRQ contexts. */ mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn, mempool_free_t *free_fn, void *pool_data) /** * mempool_alloc - allocate an element from a specific memory pool * @pool: pointer to the memory pool which was allocated via mempool_create(). * @gfp_mask: the usual allocation bitmask. * this function only sleeps if the alloc_fn() function sleeps or returns NULL. Note that due to preallocation, this function never* fails when called from process contexts. (it might fail if called from an IRQ context.) */ void * mempool_alloc(mempool_t *pool, gfp_t gfp_mask) /** * mempool_free - return an element to the pool. * @element: pool element pointer. * @pool: pointer to the memory pool which was allocated via mempool_create(). * * this function only sleeps if the free_fn() function sleeps. */ void mempool_free(void *element, mempool_t *pool) /** * mempool_destroy - deallocate a memory pool * @pool: pointer to the memory pool which was allocated via mempool_create(). * * Free all reserved elements in @pool and @pool itself. This function only sleeps if the free_fn() function sleeps. */ void mempool_destroy(mempool_t *pool)
通过本文,我们了解了Linux驱动中的内存申请技术,它们各有优缺点和适用场景。我们应该根据实际需求选择合适的函数,并遵循一些基本原则,如匹配申请和释放函数,检查返回值是否为空,避免内存泄漏等。内存申请技术是Linux驱动开发中不可或缺的一部分,它可以保证驱动程序的正常运行和数据交换,也可以提升驱动程序的性能和稳定性。希望本文能够对你有所帮助和启发。
以上がLinux ドライバーのメモリ アプリケーション テクノロジ: 原理と方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。