First of all, the following figure is the memory mapping model of Linux, which embodies several characteristics of Linux memory mapping:
- Each process has its own process space. 0-3G is user space and 3G-4G is kernel space.
- The user space of each process is not on the same physical memory page, but the kernel space of all processes corresponds to the same physical address.
- The address allocated by vmalloc can be either high-end memory or low-end memory
Memory Dynamic Request
Like the application layer, the kernel program also needs to allocate memory dynamically. The difference is that the kernel process can control whether the allocated memory is in user space or in kernel space. The former can be used to allocate memory to the heap area of user space. The malloc in user space of eg and user process will eventually call back the memory allocation function of the kernel space through the system. At this time, the memory is allocated. The allocation function belongs to the user process, which can allocate space to the heap area of the user process and return to it, eventually making a user process obtain memory allocation in its own user space; the latter allocates only the kernel space, so the user process can not directly access the space, so it is mostly used to meet the memory requirements of the kernel program itself. The following is the Linux kernel space application memory often. Using API:
kmalloc - kfree
The intrinsic physical memory of kmalloc applications is continuous, and they have only a fixed offset from the real physical address, so there is a simple conversion relationship. This API is mostly used to request less than a page size of memory. The underlying layer of kmalloc needs to call _get_free_pages. The gtp_t flags that represent the memory type in the parameters are the abbreviation of this function. The commonly used memory types are GFP_USER, GFP_KERNEL and GFP_ATOMIC.
GFP_USER represents the allocation of memory for user space pages, which can be blocked.
- GFP_KERNEL is the most commonly used flag. Note that using this flag to apply for memory, if temporarily not satisfied, will cause process blocking. So, do not use GFP_KERNEL in non-process contexts such as interrupt handler, tasklet and kernel timer!!!
GFP_ATOMIC can be used in these three situations. This flag indicates that if the memory of the application is not available, it will be returned immediately.
/** * kmalloc - allocate memory * @size: how many bytes of memory are required. * @flags: the type of memory to allocate. * The @flags argument may be one of: * %GFP_USER - Allocate memory on behalf of user. May sleep. * %GFP_KERNEL - Allocate normal kernel ram. May sleep. * %GFP_ATOMIC - Allocation will not sleep. May use emergency pools. * * For example, use this inside interrupt handlers. */ void *kmalloc(size_t size, gfp_t flags); /** * kfree - free previously allocated memory * @objp: pointer returned by kmalloc. * If @objp is NULL, no operation is performed. */ void kfree(const void *objp);
There are also API s in the same series.
void *kzalloc(size_t size, gfp_t flags)
__get_free_pages - free_pages
_ Like kmalloc(), get_free_pages() is physically contiguous memory. This series of functions is the lowest level of the Linux kernel for acquiring free memory. Because the underlying buddy algorithm manages memory by (2^n) *PAGE_SIZE, they always allocate memory in pages.
unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order) void free_pages(unsigned long addr, unsigned int order)
There are also API s in the same series.
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 - vfree
Vmalloc gives a continuous memory area in virtual memory space. In essence, this continuous virtual memory is not necessarily continuous in physical memory, so there is no simple conversion relationship between virtual memory and physical memory applied for by vmalloc. For this reason, vmalloc() is usually used to allocate memory space much larger than _get_free_pages(), and its implementation needs to establish a new one. Page table, in addition to calling kmalloc, so using GFP_KERN, do not use vmalloc in non-process contexts such as interrupt handler, tasklet and kernel timer!
/** * 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)
There are also API s in the same series.
/** * 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 cache
As we know, pages are the basic unit of memory mapping, but many frequently created objects in the kernel need less than one page of memory. If we still use page mapping, frequent allocation and release will result in waste of resources and reduce system performance. In order to solve this problem, the slab mechanism is introduced in the kernel, so that the object is allocated to the same memory or the same kind of memory space twice before and after being used, and the basic data structure is retained, which can greatly improve the efficiency. The bottom layer of kmalloc is to use slab algorithm to manage allocated memory. Note that slabs are still mapped in pages, but after the mapping, the pages are split into the same smaller units, saving memory. The slab allocated units should not be less than 32B or greater than 128K.
/** * kmem_cache_create - Create slab cache objects * @name:slab Cache name, * @size:slab The size of each cell of the allocated buffer * @align:The alignment of memory in the buffer is generally given to 0. * @flags:Controlling the allocation of bit masks, * %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)
Example
//Create slab objects 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); //Allocation of slab caches struct xj_unit_t *xj_unit; xj_unit = kmem_cache_alloc(xj_sbcache,GFP_KERNEL); /* Using slab caching */ /* Release slab cache */ kmem_cache_free(xj_sbcache, xj_unit); /* Destroy slab cache */ kmem_cache_destroy(xj_sbcache);
Memory pool
In addition to slab mechanism, the kernel also provides a traditional memory pool mechanism to manage the allocation of small blocks of memory. Memory pool is mainly used to solve the problem of memory shortage, because a memory pool has allocated a memory when it was created. When we apply for memory from a created memory pool with mempool_alloc, the function will first try to call back the allocated memory function when the memory pool was created. If there is no memory to allocate, it will make the allocated memory function. Pre-allocated memory when creating a memory pool can avoid falling into dormancy due to no memory allocation. Of course, if pre-allocated memory has been used up, it will still fall into dormancy. The purpose of slab mechanism is to improve memory utilization and memory management efficiency. The purpose of memory pool is to avoid memory allocation failure. Here is the API for memory pools provided in the kernel
/** * 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)