The implementation of the Memory Pool (I) describes the reasons for using the memory pool, the issues to be considered in the design of the memory pool, and finally provides a simple example of implementing the memory pool. Use previousArticleThe implementation scheme of the memory pool introduced in. Under certain conditions, let's look at the more general implementation of the memory pool-the implementation of the memory pool of the Apache server.
Developers of the Apache serverCodeYou can sort out the portable parts and edit them into an Apache Portable Runtime Library (apacheportable run-timelibraries), or APR for short. This library can be downloaded from here, this includes the implementation code of the memory pool to be introduced here. The Apache server memory pool is referred to as the APR memory pool.
APR Memory Pool Structure 1. Memory Allocation Node
Before learning about the entire memory pool architecture, let's first understand the most basic unit in the APR memory pool-the memory allocation node. The memory allocation node is used to describe the memory block allocated each time. The corresponding structure is apr_memnode_t, which is defined in the apr_allocator.h file. Its definition is as follows:
/* Basic memory nodestructure */struct apr_memnode_t {apr_memnode_t * Next;/** <next memnode */apr_memnode_t ** ref;/** <reference to self */apr_uint32_t index; /** <size */apr_uint32_t free_index;/**
Even if each field in the structure is annotated in the source file, it is difficult to understand the purpose of each field. Here we will give a brief analysis of each field:
- Next: pointer to the next node;
- Ref: points to the next node of the previous node, and the next node of the previous node points to the current node. Therefore, ** ref is the current node;
- Index: indicates the size of the node and the index value of the linked list where the node is located;
- Free_index: The unoccupied space in the memory block described here (this is different from the above index and their literal meaning. Pay attention to it when you understand it );
- First_avail: pointer to the starting position of the available space;
- Endp: pointer to the end of the available space.
The node is as follows:
2. Memory distributor
In the ARP memory pool, a memory distributor is used to manage the memory allocation nodes. It is defined in apr_pools.c as follows:
Struct apr_allocator_t {apr_uint32_t max_index; apr_uint32_t max_free_index; paicurrent_free_index; apr_pool_t * owner; apr_memnode_t * free [max_index];};
- Max_index: subscript of the Free pointer array. Free [max_index] points to the existing maximum memory block linked list;
- Max_free_index: maximum memory space that the memory distributor can accommodate;
- Current_free_index: The size of space that can be received by the memory distributor. It can be used with max_free_index to limit the size of the memory pool;
- Owner: indicates the memory pool to which the distributor belongs;
- Free: points to the head node of a linked list. each node in the linked list points to a linked list composed of Memory nodes. max_index is 20.
The following figure shows the Memory Distribution and Its managed Memory nodes:
We can clearly see that the subscript of the Free array from 1 to the MAX_INDEX-1, respectively pointing to a linked list with fixed node size, subscript increase 1, node size increase 4 K, therefore, the node size of the free [max_index] linked list is 84 K, which is the maximum "rule node" that the memory pool user can apply for. if the limit is exceeded, the subscripts 0 point to the linked list for management. To understand the relationship between free array subscript and node size, we need to know the macro definition apr_align:
# Defineapr_align (size, boundary) \ (size) + (Boundary)-1 ))&~ (Boundary)-1 ))
This macro is nothing more than an integer that calculates the boundary nearest to the size. Generally, the size is an integer, while boundary must be a multiple of 2. For example, apr_align () is 8, apr_align () is 24, and apr_align () is 32.
For each space application, APR first alignment the space size:
Size = apr_align (size + apr_memnode_t_size, 4096 );
The result is that the size value is a multiple of 4096 (4 K, 2 to the power of 12). Finally, the Left shift corresponds to our Subscript:
Index = (size> boundary_index)-1; // boundary_index = 12
3. Memory Pool Node
The APR memory pool node is defined as follows in the apr_pools.c file:
Struct apr_pool_t {...... Apr_allocator_t * Allocator; apr_memnode_t * active ;......};
There are many fields in this structure. We mainly focus on the two fields listed above.
- Allocator: points to the corresponding memory distributor;
- Active: pointer to the memory linked list in use
The memory pool node and its managed memory node are shown in:
It should be noted that although the structure is literally a "Memory Pool Structure", it is responsible for managing the memory in use.
APR memory pool Memory Management
After a preliminary understanding of the APR memory pool structure, we can see how APR uses these structures for memory management.
1. Memory Application
The Core Function Applied for memory is the allocator_alloc function. The parameter is a pointer to the memory distributor and the size of the space to be applied, memory allocation is to operate the memory distributor (for the fields listed below, see the "memory distributor" section). The memory application policy is as follows:
- The index is generated based on the size of the requested space. If the index value is 1 ~ Max_index is in the range of index ~ A piece of memory is returned from the linked list within the range of max_index;
- If the index value is> max_index, find a suitable memory in the free [0] linked list;
- If no idle memory block is found in the last two steps, a new memory block is returned through malloc (size.
2. Memory release
As mentioned in the memory application, if there is no suitable memory block in the memory distributor, malloc will be called to obtain one, but the newly allocated memory is not attached to the memory distributor linked list, instead, when allocator_free is called to release the memory, the memory can be mounted to the memory distributor linked list. The memory release policy is as follows:
- If the node size exceeds the full release threshold value of max_free_index, we cannot simply return it to the index linked list, but must completely return it to the operating system;
- If index <max_index, it means that the node is within the range of "rule node. Therefore, the node can be returned to the corresponding "rule linked list;
- If the node exceeds the range of the "rule node" but does not exceed the threshold value of max_free_index, we can place it in the header of the "index 0" linked list.
3. Memory managed by memory pool nodes
At the beginning, the linked list managed by the memory distributor did not mount any memory. That is to say, the memory pool is empty. When we apply for memory, we must perform step 3 in "memory application, the newly allocated memory is managed by our memory pool node.
Let's take a look at a macro definition for memory pool node management:
/* Node list managementhelper macros; list_insert () inserts 'node' * Before 'point '. */# define list_insert (node, point) do {\ node-> ref = point-> ref; \ * node-> ref = node; \ node-> next = point; \ point-> ref = & node-> next; \} while (0)
When a memory pool node is created for the first time, the linked list status is as follows:
Apply for a node again and run list_insert (node, point). The result is as follows:
We can use allocator_free call or apr_pool_clear and apr_pool_destroy call (they call allocator_free internally) to release memory pool nodes, the released memory will be returned to the memory pool or operating system according to the "memory release" policy.
Summary
The double meaning of the sub-mark of the Free array (that is, the array subscript and memory block size), and the limit on the memory pool size through the que value max_free_index are hard to understand, but it is also part of the APR memory pool implementation. In addition, the APR memory pool also involves the concept of parent/child/sibling memory pool and memory pool lifecycle, students can learn more deeply through the reference documents provided at the end of the article.
Reference: Apache memory pool insider