内存池的实现与场景分析

内存管理库

  • jemalloc 内存管理,C 语言。
  • tcmalloc 内存管理,C++。
  • 在头文件中引入即可。

确定 block 的大小、不确定 block 的释放时间,如何设计内存池 ?

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>

// gcc mem_pool_v1.c -o  mem_pool_v1

#define MEM_PAGE_SIZE		4096

typedef struct mempool_s {
    int block_size; // 每个 block 的大小
    int free_count; // 可分配的 block 的数量

    char *free_ptr; // 指向可分配的 block 的起始位置
    char *mem;      // 指向内存块的起始位置
} mempool_t;


int mp_init(mempool_t *m, int size) {

	if (!m) return -1;
	if (size < 16) size = 16;

	m->block_size = size;

	m->mem = (char *)malloc(MEM_PAGE_SIZE);
	if (!m->mem) return -1;
	m->free_ptr = m->mem;
	m->free_count = MEM_PAGE_SIZE / size;

	int i = 0;
	char *ptr = m->free_ptr;
	for (i = 0;i < m->free_count;i++) {
		*(char **)ptr = ptr + size;
		ptr += size;
	}
	*(char **)ptr = NULL;

	return 0;
}

void mp_dest(mempool_t *m) {
	if (!m || !m->mem) return ;
	
	free(m->mem);

}


void *mp_alloc(mempool_t *m) {

	if (!m || m->free_count == 0) return NULL;

	void *ptr = m->free_ptr;

	m->free_ptr = *(char **)ptr;
	m->free_count --;
	
	return ptr;
}


void mp_free(mempool_t *m, void *ptr) {

	*(char **)ptr = m->free_ptr;
	m->free_ptr = (char *)ptr;
	m->free_count ++;
}


int main() {

	mempool_t m;

	mp_init(&m, 32);

	void *p1 = mp_alloc(&m);
	printf("1: mp_alloc: %p\n", p1);

	void *p2 = mp_alloc(&m);
	printf("2: mp_alloc: %p\n", p2);

	void *p3 = mp_alloc(&m);
	printf("3: mp_alloc: %p\n", p3);

	void *p4 = mp_alloc(&m);
	printf("4: mp_alloc: %p\n", p4);

	mp_free(&m, p2);

	void *p5 = mp_alloc(&m);
	printf("5: mp_alloc: %p\n", p5);
	

	return 0;
}

不确定 block 的大小,确定 block 的释放时间,如何设计内存池 ?

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>

#define MEM_PAGE_SIZE		4096


typedef struct mp_node_s {
	char *free_ptr;
	char *end;
	struct mp_node_s *next;
} mp_node_t;


typedef struct mp_pool_s {
	struct mp_node_s *first;   // 指向第一个节点
	struct mp_node_s *current; // 指向当前可用的节点
	int max; // page size
} mp_pool_t;


int mp_init(mp_pool_t *m, int size) {

	if (!m) return -1;

	void *addr = malloc(size); // 4096
	mp_node_t *node = (mp_node_t*)addr;
	
	node->free_ptr = (char*)addr + sizeof(mp_node_t);
	node->end = (char*)addr + size;
	node->next = NULL;

	m->first = node;
	m->current = node;
	m->max = size;

	return 0;

}


void mp_dest(mp_pool_t *m) {

	if (!m) return ;

	while (!m->first) {

		void *addr = m->first;
		mp_node_t *node = (mp_node_t*)addr;

		m->first = node->next;

		free(addr);
	}
	
	return ;
}

void *mp_alloc(mp_pool_t *m, int size) {   // size < (4096-sizeof(mp_node_t))

	void *addr = m->current;
	mp_node_t *node = (mp_node_t*)addr;

	do {
		if (size <= (node->end - node->free_ptr)) {  

			char *ptr = node->free_ptr;
			node->free_ptr += size;

			return ptr;
			
		}
		node = node->next;
		
	} while (node);

	// new node

	addr = malloc(m->max); // 4096
	node = (mp_node_t*)addr;

	node->free_ptr = (char*)addr + sizeof(mp_node_t);
	node->end = (char*)addr + m->max;

	// 头插法
	node->next = m->current;
	m->current = node;

	char *ptr = node->free_ptr;
	node->free_ptr += size;

	return ptr;

}


int main() {
	mp_pool_t m;

	mp_init(&m, MEM_PAGE_SIZE);

	void *p1 = mp_alloc(&m, 16);
	printf("1: mp_alloc: %p\n", p1);

	void *p2 = mp_alloc(&m, 32);
	printf("2: mp_alloc: %p\n", p2);

	void *p3 = mp_alloc(&m, 64);
	printf("3: mp_alloc: %p\n", p3);

	void *p4 = mp_alloc(&m, 128);
	printf("4: mp_alloc: %p\n", p4);

	void *p5 = mp_alloc(&m, 256);
	printf("5: mp_alloc: %p\n", p5);

	mp_dest(&m);

}

内存池的好处

  • 内存池是内存块的管理组件
  • 首先要分配整块内存, 然后为整块内存制定一些策略,如果内存不够,就再分配一块。
  • 避免了小块的内存分配,避免了频繁地向操作系统申请内存
  • 避免了长期运行出现的内存碎片

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-31 22:58:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-31 22:58:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-03-31 22:58:03       82 阅读
  4. Python语言-面向对象

    2024-03-31 22:58:03       91 阅读

热门阅读

  1. 输入 wo xiang he ni jao peng you.,倒着打。

    2024-03-31 22:58:03       44 阅读
  2. NC20128 不重复数字

    2024-03-31 22:58:03       39 阅读
  3. ES6:Map()与WeakMap()

    2024-03-31 22:58:03       39 阅读
  4. 探索Vue脚手架:构建现代化Web应用的利器

    2024-03-31 22:58:03       38 阅读
  5. 网页的皮肤——css

    2024-03-31 22:58:03       36 阅读
  6. 【对图书的ISBN 号码进行识别处理】

    2024-03-31 22:58:03       43 阅读
  7. 达梦数据库 创建外部表 [-7082]:外部表数据错误.

    2024-03-31 22:58:03       41 阅读
  8. Linux-基础环境搭建

    2024-03-31 22:58:03       39 阅读