C language dynamic memory management
1-Overview
The basic problem of dynamic storage management is: how the system allocates memory as requested and how to recycle the memory. The user who initiates the request may be a system job or a variable in the program.
Idle Block
Memory areas with unallocated addresses are called "Idle blocks ".
Occupied block
The memory area that has been allocated to the address used by the user is called "occupied block ".
When the system is just started, the entire memory can be regarded as a large "Idle block". As user requests enter, the system allocates the corresponding memory in sequence.
During system operation, the memory is divided into two major parts: Low-address zone (several occupied blocks) and high-address zone (idle blocks ).
After a period of time, some programs run to an end and release the memory occupied by the program to change it into idle blocks, this makes the free block and occupied block in the entire memory staggered. For example:
When the system enters B in the figure, and there are new user requests to allocate memory, what should the system do?
Method 1: the system continues to allocate idle blocks in the high address area until they cannot be allocated. When the remaining idle blocks cannot meet the allocation request, the system recycles all the memory areas that are no longer in use and re-organizes the memory. compact all the idle blocks into a large idle block, for allocation.
Method 2:Idle linked list. The idle linked list contains information about all idle blocks. One node corresponds to one idle block. When a user requests allocation, the system searches for idle linked lists, finds a suitable idle block based on a certain policy, and deletes the corresponding node. When the user releases the occupied memory, the system recycles the memory and inserts it into the idle linked list.
Idle linked list
Three structures of idle linked list:
(1) The memory size of all requests is the same. This is the simplest way to manage dynamic storage.
In this regard, the system's common practice is:
A) when the system starts, the memory is divided into several blocks by size to form a linked list.
B) when allocating, you only need to allocate the first node in the linked list to the user, without scanning the entire linked list.
C) When recycling, insert the idle block into the linked list header.
(2) The memory size of all requests is in n specifications. You can create n (1) linked lists. Distribution and recycling are similar to (1). The difference is that when the requested linked list is empty, you need to allocate resources on the linked list with a large node, fetch some memory for the user, and insert the remaining part as a new node to the corresponding linked list.
(3) The memory size of all requests varies constantly. In this case, the allocation and recycling are described in the next article.
Allocation Algorithm and collection
For idle linked lists with different memory block sizes, if there is a memory application with a size of N, if there is only one memory larger than N in the idle linked list, if the size is M, the M part is allocated to the user, and the rest of the M-N as a node into the idle linked list.
How can we allocate multiple blocks of memory greater than N? There are usually three methods:
(1) first adaptation method. As the name suggests, scan the idle linked list sequentially, find the first idle block greater than or equal to N, and assign N to the user. Because the linked list is not sorted by memory address or by size, you just need to recycle the memory block and put it in the header.
Problem: after running for a period of time, some very small blocks will appear in the linked list, and all these small blocks are in the front of the linked list.
(2) optimal adaptation method. Find an idle block not less than N and closest to N in the idle linked list and assign it to the user. Full table scan is required during allocation. If the linked list is sorted from small to large by idle blocks, you only need to find the first idle block greater than N during allocation, and insert it to the proper position of the linked list during recycling.
(3) Worst adaptation method. Allocate a part of the free block in the linked list that is not less than N and the largest in the linked list to the user. The linked list can be arranged in ascending order of idle blocks. You only need to determine the first idle block of the linked list for allocation. during recycling, You need to insert it to the proper position of the linked list.
For recycling, we consider not only returning nodes, but also merging idle blocks. This method is required to merge adjacent idle blocks of physical addresses to obtain larger idle blocks. The idle blocks in the idle linked list are not ordered by physical addresses. How can we merge them quickly? In the next article, we will discuss a method: the boundary identification method.
Boundary Identification
Link: http://blog.csdn.net/hbuxiaoshe/article/details/5994743
As for idle linked lists, it is not easy to determine which idle blocks are physically adjacent to the physical addresses. It is necessary to scan the entire table.
Boundary IdentificationIt can effectively determine whether the physical adjacent memory blocks of idle blocks are idle blocks.
All idle blocks form a two-way circular linked list. The structure of each node in the linked list is as follows:
Llink and rlink point to the frontend and successor nodes in the linked list respectively.
Size indicates the size of the memory block.
Uplink points to the first address of the block. The arrow in the figure describes the function of uplink.
Each tag header and tail are identified as the memory block boundary. Table 0 is free and table 1 occupies blocks.
During allocation, many very small idle blocks are generated on the linked list, which affects the allocation efficiency. Therefore, a global pointer p can be defined and allocated when it is not empty, always point to the successor node of the node that has just been allocated.
How to determine whether physical adjacent blocks are idle blocks during recovery:
Assume that the physical address of the recycled block is p (the left and right adjacent blocks involved in the following are physically adjacent, and may not be adjacent in the linked list ),
Left adjacent Block: The end address of the Left adjacent block is p1 = p-sizeof (tail), and whether the left adjacent block is idle block is determined by p1-> whether the tag is 0. When it is an idle block, you only need to merge the current block into the left adjacent block, the address of the Left adjacent block needs to be obtained by uplink (because the size of the intermediate memory block is not fixed and cannot be offset), that is, p1-> uplink. Modify the size and uplink of the Left adjacent block.
Right adjacent Block: The first address of the right adjacent block is p2 = p + sizeof (header), and the right adjacent block is determined as idle block by p2-> tag is 0. When it is an idle block, merge it with the right adjacent block, modify the llink, rlink, and size of p, and modify the uplink of p2.
You may think that since the blocks in the linked list are all idle blocks, why should we Add tag identifiers? My answer is: if there is no tag, when we find the address of the right adjacent block, there is no way to determine whether the right adjacent block is a node in the linked list. Maybe it is still being used by users. So why should we use two tags? I personally think that one can be used, but it is easier to use two.