Memory Learning (8): Block Allocator 1

1. Overview of the block allocator

We know the page allocator before, but there are certain usage scenarios that are not satisfactory, so here we introduce the block allocator, which has a smaller granularity in memory allocation.

The role of the SLAB allocator is not only to allocate small blocks of memory, but also to act as a cache for frequently allocated and released objects.

The core idea of ​​the SLAB allocator is: create a memory cache for each object type , each memory cache consists of multiple large blocks (slab, the original meaning is a large block of concrete), a large block is one or more contiguous physical pages, each chunk contains multiple objects.

SLAB adopts object-oriented thinking and manages memory based on object types. Each object is divided into a class . For example, a process descriptor (task_struct) is a class, and each process descriptor instance is an object. The composition of the memory cache is shown in Figure 3.21.

The SLAB allocator does not perform very well in some cases, so the Linux kernel provides two improved block allocators.

  • (1) On a large computer equipped with a large amount of physical memory, the memory overhead of the management data structure of the SLAB allocator is relatively large, so the SLUB allocator is designed.
  • (2) On embedded devices with small memory, the code of the SLAB allocator is too much and too complicated, so a simplified SLOB allocator is designed. SLOB is the abbreviation of "Simple List Of Blocks", which means a simple block list. Currently the SLUB allocator has become the default block allocator.

2. Programming interface

Three block allocators provide a unified programming interface.

For ease of use, the block allocator creates some common memory caches during initialization. The length of the object is mostly 2n bytes. The name of the memory cache that allocates pages from the common area is "kmalloc-" (size is the length of the object ), the name of the memory cache that allocates pages from the DMA area is "dma-kmalloc-", and you can see these common memory caches by executing the command "cat /proc/slabinfo" .

The general memory cache programming interface is as follows.

(1) Allocate memory.

    void *kmalloc(size_t size, gfp_t flags);
  • size: the required memory length.
  • flags: The allocation flag bit passed to the page allocator. This allocation flag bit is used when there is no free object in the memory cache and the page allocator is requested to allocate a page.

The block allocator finds a suitable general memory cache: the object's length is just greater than or equal to the requested memory length, and allocates the object from this memory cache. If the allocation is successful, the address of the object is returned, otherwise a null pointer is returned.

(2) Reallocate memory.

    void *krealloc(const void *p, size_t new_size, gfp_t flags);
  • p: The object that needs to reallocate memory.
  • new_size: the new length.
  • flags: Flags passed to the page allocator.

Reallocate memory for the object according to the new length. If the allocation is successful, return the new address, otherwise return a null pointer.

(3) Release the memory.

    void kfree(const void *objp);
  • objp: The address of the object returned by kmalloc().

Here is a thought question: How does the kfree function know which general memory cache the object belongs to? Answer later.

special interface

1- Create a dedicated memory cache

The disadvantage of using a general-purpose memory cache is that the block allocator needs to find a general-purpose memory cache whose object length is just greater than or equal to the requested memory length. If the requested memory length is far from the object length of the memory cache, the waste is relatively large. For example, if you apply for 36 bytes, the actual allocated memory length is 64 bytes, wasting 28 bytes.

So sometimes users need to create a dedicated memory cache, the programming interface is as follows.

    struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align,unsigned long flags, void (*ctor)(void *));
  • name: name.
  • size: the length of the object.
  • align: The value to which the object needs to be aligned.
  • flags: SLAB flag.
  • ctor: The constructor of the object.

If the creation is successful, return the address of the memory cache, otherwise return a null pointer.

2 - Allocate the object from the specified memory cache.

    void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags);
  • cachep: allocate from the specified memory cache.
  • flags: The allocation flag bit passed to the page allocator. This allocation flag bit is used when there is no free object in the memory cache and the page allocator is requested to allocate a page.

If the allocation is successful, the address of the object is returned, otherwise a null pointer is returned.

3- Release the object.

    void kmem_cache_free(struct kmem_cache *cachep, void *objp);
  • cachep: The memory cache to which the object belongs.
  • objp: the address of the object.

4- Destroy memory cache.

    void kmem_cache_destroy(struct kmem_cache *s);
  • s: memory cache.

In the next article, let's take a look at the three types of block allocators.

Reference content "In-depth analysis of Linux kernel"

Guess you like

Origin blog.csdn.net/weixin_45264425/article/details/129504011