当前位置:网站首页>Handwritten memory pool and principle code analysis [C language]
Handwritten memory pool and principle code analysis [C language]
2022-04-23 02:15:00 【Linux server development】
Memory pool is to manage the heap
When the process executes , The operating system will separate 0~4G Virtual memory space for the process , Programmers can manage ( Distribute 、 Release ) The most important part is mmap Mapping area 、heap Heap area , The part of memory pool management is the heap of user processes .
Why use a memory pool ?
Memory pool is used to avoid fragmentation of heap area
-
Avoid frequently allocating and freeing memory ( Prevent fragmentation in the heap area )
When the client connects to the server , The server will prepare part of the heap for message retention . When a connection succeeds , The server will allocate a section of memory belonging to this connection in the heap , When the connection is closed , The allocated memory is also released . But when the number of connections is large and too frequent , Inevitably, memory is allocated and released frequently . This will cause small windows in the heap area , That is, heap fragmentation .
What happens if there is fragmentation in the heap area ?
-
Working for a long time will lead to undetectable BUG
-
Unable to allocate large and whole block of memory ,malloc Returns the NULL
Memory pool design
scene : In a very clean pile area , How to implement a memory pool that can avoid memory fragmentation ?
First of all : Use linked list to manage memory
Use the linked list to connect the allocated memory in the heap area one by one , Set up flag( Is it used ), Let each segment of memory on the linked list node expand slowly .
What problems will occur when using the linked list alone ?
-
Memory blocks will be divided smaller and smaller , The linked list will become longer and longer , Know you can't partition out much more memory .
So the design with the idea of fixed memory
For allocating small segments of memory , Divide small segments of memory into fixed segments , as follows
-
16bytes
-
32bytes
-
64bytes
-
128bytes
-
256byts
-
512bytes
However, different fixed small memory allocation will lead to the following problems :
1. Search slow
Find when allocating
Find when releasing
2. There will also be gaps between blocks
Cannot merge blocks
It's troublesome to recycle small pieces
So finally, we get the memory pool model of custom fixed block and random block
Memory pool
Memory pool workflow

Memory pool structure
// Memory pool
struct mp_pool_s{
size_t max;
struct mp_node_s *current; // The small memory area currently pointed to , Chain table structure
struct mp_large_s *large; // Big memory
struct mp_node_s *head[0]; // The head of a small piece of memory
};
Small pieces of memory are linked by a one-way linked list
// Small memory
struct mp_node_s{
unsigned char *last; // Current
unsigned char *end; // Last
struct mp_node_s *next; // next 4k
size_t failed;
};
Large blocks of memory are also linked by one-way linked lists
// Big memory
struct mp_large_s{
struct mp_large_s *next;
void *alloc;
};
API
Create a memory pool
-
Make sure to size Size is the fixed size of small memory
-
One is last Point to the first byte of the node
-
end Point to the last
// Create a memory pool
struct mp_pool_s *mp_create_pool(int size){
struct mp_pool_s *pool;
int ret = posix_memalign((void**)&pool, ALIGNMENT, size + sizeof(struct mp_pool_s) + sizeof(struct mp_node_s));
if(ret)return NULL;
pool->max = (size<MP_MAX_ALLOC_FORM_POOL) ? size : MP_MAX_ALLOC_FORM_POOL;
pool->current = pool->head;
pool->head->last = (unsigned char*)pool + sizeof(struct mp_pool_s) + sizeof(struct mp_node_s);
pool->head->end = pool->head->last + size;
pool->head->failed = 0;
pool->large = NULL;
return pool;
}
Destroy the memory pool
-
Free a large block of memory first , Traversing the linked list
-
Then release the small pieces , Traversing the linked list
// Destroy the memory pool
void mp_destroy_pool(struct mp_pool_s *pool){
struct mp_large_s *large;
for(large = pool->large; large!=NULL; large = large->next){ // Release chunk
if(large->alloc)free(large->alloc);
}
struct mp_node_s *h = pool->head->next;
while(h){ // Release small pieces
struct mp_pool_s *next = h->next;
free(h);
h = h->next;
}
free(pool);
}
Reset memory pool
-
Free a large block of memory first
-
Then put a small piece of memory last Point to the first location of memory
// Reset memory pool
void mp_reset_pool(struct mp_pool_s *pool){
struct mp_node_s *head;
struct mp_large_s *large;
for(large = pool->large; large; large=large->next){ // Will release large chunks
if(large->alloc)free(large->alloc);
}
pool->large = NULL;
for(head = pool->head; head; head = head->next){ // Point the head position of each node to the position just created
head->last = (unsigned char*)head + sizeof(struct mp_node_s);
}
}
Allocate a small amount of memory to the memory pool
-
First allocate a whole block ( The size is psize) Small memory , And create a node to point to this memory
-
Memory alignment , Use the tail insertion method to insert the last position of the linked list
-
Readjust the memory pool current The direction of
/* Distribute psize Small chunks of memory , Where to start pointing head->last = memblk + size, List tail insertion method */
static void *mp_alloc_block(struct mp_pool_s *pool, size_t size){
unsigned char *memblk;
struct mp_node_s *head = pool->head;
size_t psize = (size_t)(head->end - (unsigned char*)head); //psize == Parameters entered when creating memory pool
int ret = posix_memalign((void*)&memblk, ALIGNMENT, psize); // Allocate memory 24 Byte alignment
if(ret)return NULL;
struct mp_node_s *p, *new_node, *current;
new_node = (struct mp_node_s*)memblk;
new_node->end = memblk + psize;
new_node->next = NULL;
new_node->failed = 0;
memblk += sizeof(struct mp_node_s); // Skip node structure for memory alignment
memblk = mp_align_ptr(memblk, ALIGNMENT); // Memory alignment
new_node->last = memblk + size;
current = pool->current;
for(p = current; p->next; p = p->next){ // The tail interpolation
if(p->failed++>4)current = p->next;
}
p->next = new_node;
pool->current = current ? current : new_node;
return memblk;
}
Take out a piece of memory size Size of memory ( No byte alignment )
-
First, get the small block of memory pointed to by the current memory pool
-
Follow one node by one to find out whether there is enough memory in the small memory size Size of memory allocation
-
If so, byte align the memory and return
-
If there is no suitable small block of memory, allocate an extra small block of memory
-
If the small memory allocation fails , To create a large block of memory size Distribute
// Take a block from a small memory area size Size of memory
void *mp_nalloc(struct mp_pool_s *pool, size_t size){
unsigned char *m;
struct mp_node_s *p;
if(size<=pool->max){
p = pool->current; // The current block points to
do{
m = p->last;
if((size_t)(p->end - m)>=size){ // If the remaining memory ratio of the current node size If it is large, it will be allocated at this node
p->last = m + size;
return m;
}
p = p->last;
// If the remaining size of no section is greater than size Just reassign one block
}while(p);
return mp_alloc_block(pool, size);
}
// If this size Exceeded the limit of small memory , It is distributed in the way of large block content distribution
return mp_alloc_large(pool, size);
}
Take out a piece of memory size Size of memory ( Do byte alignment )
// Take a block from a small memory area size Size of memory Byte alignment
void *mp_alloc(struct mp_pool_s *pool, size_t size){
unsigned char *memblk;
struct mp_pool_s *p;
if(size<=pool->max){
p = pool->current; // The current block points to
do{
memblk = mp_align_ptr(p->last, ALIGNMENT);// Do byte alignment
if((size_t)(p->end-memblk) >= size){ // If the remaining memory ratio of the current node size If it is large, it will be allocated at this node
p->last = memblk + size;
return memblk;
}
p = p->next;
}while(p);
// If the remaining size of no section is greater than size Just reassign one block
return mp_alloc_block(pool, size);
}
// If this size Exceeded the limit of small memory , It is distributed in the way of large block content distribution
return mp_alloc_large(pool, size);
}
Take out a piece of memory size Size of memory and initialize to 0
// Allocate memory and initialize to 0
void *mp_calloc(struct mp_pool_s *pool, size_t size){
void *p = mp_alloc(pool, size);
if(p){
memset(p, 0 , size);
}
return p;
}
Distribute size Large chunks of memory ( Large memory nodes are placed in small memory )
-
First malloc Get the first memory address , Then hang the large memory on the memory pool , If the structure of large memory is not created, it will be created in small memory
-
After creation, hook up and return the first address of large memory
// Create large blocks of memory
static void *mp_alloc_large(struct mp_pool_s *pool, size_t size){
void *p = malloc(size); // Distribute
if(p==NULL)return NULL;
size_t n = 0;
struct mp_large_s *large;
for(large=pool->large; large; large = large->next){
if(large->alloc == NULL){
large->alloc = p;
return p;
}
if(n++>3)break;
}
// The memory is not large
large = mp_alloc(pool, sizeof(struct mp_large_s));
if(large==NULL){
free(large);
return NULL;
}
large->alloc = p;
large->next = pool->large;
pool->large = large;
return p;
}
Free a specified chunk of memory p
-
Find and then release
// Free memory p
void mp_free(struct mp_pool_s *pool, void *p){
struct mp_large_s * large;
for(large = pool->large; large; large = large->next){
if(p==large->alloc){
free(large->alloc);
large->alloc = NULL;
return;
}
}
heavy load posix_memalign
// restructure mem_memalign
void *mp_memalign(struct mp_pool_s *pool, size_t size, size_t alignment){
void *p;
int ret = posix_memalign(&p, alignment, size);
if(ret){
return NULL;
}
struct mp_large_s *large = mp_alloc(pool, sizeof(struct mp_large_s ));
if(ret)return NULL;
struct mp_large_s *large = mp_alloc(pool, sizeof(struct mp_large_s));
if(large==NULL){
free(p);
return NULL;
}
large->alloc = p;
large->next = pool->large;
pool->large = large;
return p;
}
Memory alignment formula
#define MP_ALIGNMENT 32
#define MP_PAGE_SIZE 4096
#define MP_MAX_ALLOC_FROM_POOL (MP_PAGE_SIZE-1)
#define mp_align(n, alignment) (((n)+(alignment-1)) & ~(alignment-1))
#define mp_align_ptr(p, alignment) (void *)((((size_t)p)+(alignment-1)) & ~(alignment-1))
thus , All the contents of the memory pool are here
Recommend to see nginx The memory pool of , Of this memory pool demo and nginx It's very similar
版权声明
本文为[Linux server development]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204230210134323.html
边栏推荐
- Gray scale range corresponding to colors (red, yellow, green, blue, purple, pink, brick red and magenta) in HSV color space
- C standard library - < time h>
- R language advanced | generalized vector and attribute analysis
- JDBC cannot connect to MySQL, and the error is access denied for user 'root' @ '* * *' (using password: Yes)
- What business scenarios will the BGP server be used in?
- World Book Day 𞓜 a good book that technicians should not miss (it cutting-edge technology)
- Use Xdebug breakpoint debugging in postman
- Thinkphp内核开发盲盒商城源码v2.0 对接易支付/阿里云短信/七牛云存储
- 不断下沉的咖啡业,是虚假的繁荣还是破局的前夜?
- Numerical remapping method (remap)
猜你喜欢
How to choose a good dial-up server?
day18--栈队列
They are all intelligent in the whole house. What's the difference between aqara and homekit?
How to call out services in idea and display the startup class in services
【无标题】
001_ Redis set survival time
Some tips for using proxy IP.
都是做全屋智能的,Aqara和HomeKit到底有什么不同?
R language advanced | generalized vector and attribute analysis
How to recognize products from the perspective of Dialectics
随机推荐
[NK] Niuke monthly race 48 D
假如404页面是这样的 | 每日趣闻
013_ Analysis of SMS verification code login process based on session
PTA: Romantic reflection [binary tree reconstruction] [depth first traversal]
Arduino esp8266 network upgrade OTA
PHP sorting of interview questions on April 20, 2022
Leetcode46 Full Permutation
MySQL C language connection
数仓建表111111
IAR embedded development stm32f103c8t6 Lighting LED
If 404 page is like this | daily anecdotes
Why is one plus one equal to two
Consider defining a bean of type 'com netflix. discovery. AbstractDiscoveryClientOptionalArgs‘
简洁开源的一款导航网站源码
leetcode:27. Remove element [count remove]
【dpdk】10. Dpdk DNS learning notes
Synchronized锁及其膨胀
一加一为什么等于二
hyperscan --- 1
Leetcode40 - total number of combinations II