Nginx内存池仿写和测试
【Nginx内存池源码刨析】
使用C++语言将Nginx内存池封装成面向对象内存池,将内存池的创建和销毁实现在构造函数和析构函数中。
Nginx内存池代码
ngx_mem_pool.h文件
#ifndef NGX_MEM_POOL_H
#define NGX_MEM_POOL_H
#include <cstdlib>
#include <cstring>
// Nginx内存池的主要类型定义
using u_char = unsigned char;
using ngx_uint_t = unsigned int;
// 外部资源释放结构体类型
typedef void(*ngx_pool_cleanup_pt)(void *data); // 回调函数指针
struct ngx_pool_cleanup_s
{
ngx_pool_cleanup_pt handler; // 回调函数指针
void *data; // 传入回调函数的实参
ngx_pool_cleanup_s *next; // 指向下一个外部资源释放结构体类型
};
// 大块内存的头信息
struct ngx_pool_large_s {
ngx_pool_large_s *next; // 指向下一个大块内存的头部
void *alloc; // 指向开辟内存的首地址
};
// 内存池中分配内存的小块内存的内存块头信息
struct ngx_pool_s; // 类型声明
struct ngx_pool_data_s {
u_char *last; // 指向内存块可用内存起始位置
u_char *end; // 指向内存块可用内存末尾位置
ngx_pool_s *next; // 指向下一个内存块
ngx_uint_t failed; // 记录当前内存块开辟小块内存失败次数
};
// 内存池的头部信息
struct ngx_pool_s {
ngx_pool_data_s d;
size_t max; // 小块内存和大块内存的界限
ngx_pool_s *current; // 指向小块内存池中第一块可用内存块
ngx_pool_large_s *large; // 记录大块内存的链表起始地址
ngx_pool_cleanup_s *cleanup; // 记录释放外部资源的链表起始地址
// ngx_chain_t *chain; 这个暂时不用
// ngx_log_t *log; 这个是ngx的日志
};
// 一个物理页面的大小4k
const int ngx_pagesize = 4096;
// ngx定义小块内存最大可分配一个页面 4k
const int NGX_MAX_ALLOC_FROM_POOL = ngx_pagesize - 1;
// ngx内存池默认大小,16k
const int NGX_DEFAULT_POOL_SIZE = 16 * 1024;
// ngx内存对齐是以16为基准的
const int NGX_POOL_ALIGNMENT = 16;
// 将d的大小提升为a的倍数
#define ngx_align(d, a) (((d) + (a - 1)) & ~(a - 1))
// ngx内存池最小字节数,因为至少需要存放内存池的头信息
const int NGX_MIN_POOL_SIZE =
ngx_align((sizeof(ngx_pool_s) + 2 * sizeof(ngx_pool_large_s)),
NGX_POOL_ALIGNMENT);
// NGX对齐方式是平台unsigned long
const int NGX_ALIGNMENT = sizeof(unsigned long);
// 将p大小提升为a的倍数
#define ngx_align_ptr(p, a) (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
class Ngx_mem_pool
{
public:
// 将内存池的构造和销毁直接写入构造和析构函数中
Ngx_mem_pool(size_t size);
~Ngx_mem_pool();
// 创建内存池
//bool ngx_create_pool(size_t size);
// 释放内存池
//void ngx_destroy_pool();
// 重置内存池
void ngx_reset_pool();
// 从内存池中开辟内存,并且考虑内存对齐
void* ngx_palloc( size_t size);
// 从内存池中开辟内存,不考虑内存对齐
void* ngx_pnalloc( size_t size);
// 从内存池中开辟内存,调用的是ngx_palloc,并初始化为0
void* ngx_pcalloc( size_t size);
// 大块内存释放函数
bool ngx_pfree(void *p);
// 添加回调清理函数
ngx_pool_cleanup_s * ngx_pool_cleanup_add(size_t size);
private:
// 小块内存分配
void * ngx_palloc_small(size_t size, ngx_uint_t align);
// 大块内存分配
void* ngx_palloc_large(size_t size);
// 分配小块内存块函数
void* ngx_palloc_block(size_t size);
// 开辟内存函数,调用malloc
void* ngx_alloc(size_t size);
ngx_pool_s *pool;
};
#endif // !NGX_MEM_POOL_H
ngx_mem_pool.cpp文件
#include "ngx_mem_pool.h"
// 创建内存池
Ngx_mem_pool::Ngx_mem_pool(size_t size)
{
// 调用malloc开辟内存
pool =(ngx_pool_s*) ngx_alloc(size);
if (pool == nullptr)
{
throw"mem pool failed!";
}
// last指向当前内存块中可用内存起始地址
pool->d.last = (u_char *)pool + sizeof(ngx_pool_s);
pool->d.end = (u_char *)pool + size; // end指向当前内存块末尾地址
pool->d.next = nullptr;
pool->d.failed = 0;
// size 如果小于4k,max = size 否则 max = 4095
size = size - sizeof(ngx_pool_s);
pool->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;
pool->current = pool;
pool->large = nullptr;
pool->cleanup = nullptr;
// p->chain = NULL;
// p->log = log;
}
// 释放内存池
Ngx_mem_pool::~Ngx_mem_pool()
{
ngx_pool_s *p, *n;
ngx_pool_large_s *l;
ngx_pool_cleanup_s *c;
// 遍历外部资源的头部,调用回调函数释放外部资源
for (c = pool->cleanup; c != nullptr; c = c->next)
{
if (c->handler != nullptr)
{
c->handler(c->data);
}
}
// 遍历大块内存头信息,释放大块内存
for (l = pool->large; l != nullptr; l = l->next)
{
if (l->alloc != nullptr)
{
free(l->alloc);
}
}
// 遍历整个内存池,释放所有小块内存内存块
for (p = pool, n = pool->d.next;; p = n, n = n->d.next)
{
free(p);
if (n == NULL)
{
break;
}
}
}
// 重置内存池
void Ngx_mem_pool::ngx_reset_pool()
{
ngx_pool_s *p;
ngx_pool_large_s *l;
for (l = pool->large; l != nullptr; l = l->next)
{
if (l->alloc != nullptr)
{
free(l->alloc);
}
}
/*
for (p = pool; p != nullptr; p = p->d.next)
{
p->d.last = (u_char *)p + sizeof(ngx_pool_s);
p->d.failed = 0;
}
*/
// 将内存池中第一个内存块单独重置,因为它的头部信息较多
p = pool;
p->d.last = (u_char *)p + sizeof(ngx_pool_s);
p->d.failed = 0;
// 重置其他内存块
for (p = pool->d.next; p != nullptr; p = p->d.next)
{
p->d.last = (u_char *)p + sizeof(ngx_pool_data_s);
p->d.failed = 0;
}
pool->current = pool;
pool->large = nullptr;
//pool->chain = NULL;
}
// 从内存池中开辟内存,并且考虑内存对齐
void* Ngx_mem_pool::ngx_palloc(size_t size)
{
if (size <= pool->max)// 小块内存
{
return ngx_palloc_small(size, 1);
}
// 大块内存
return ngx_palloc_large(size);
}
// 从内存池中开辟内存,不考虑内存对齐
void* Ngx_mem_pool::ngx_pnalloc(size_t size)
{
if (size <= pool->max)// 小块内存
{
return ngx_palloc_small(size, 0);
}
// 大块内存
return ngx_palloc_large(size);
}
// 从内存池中开辟内存,调用的是ngx_palloc,并初始化为0
void* Ngx_mem_pool::ngx_pcalloc(size_t size)
{
void *p;
p = ngx_palloc(size); // 开辟内存
if (p)
{ // 将内存清0
memset(p, 0, size);
}
return p;
}
// 大块内存释放函数
bool Ngx_mem_pool::ngx_pfree(void *p)
{
ngx_pool_large_s *l;
for (l = pool->large; l != nullptr; l = l->next)
{
if (p == l->alloc)
{
free(l->alloc);
l->alloc = nullptr;
return true;
}
}
return false;
}
// 添加回调清理函数
ngx_pool_cleanup_s * Ngx_mem_pool::ngx_pool_cleanup_add(size_t size)
{
ngx_pool_cleanup_s *c;
// 在小块内存池中开辟外部资源结构体
c = (ngx_pool_cleanup_s*)ngx_palloc(sizeof(ngx_pool_cleanup_s));
if (c == nullptr)
{
return nullptr;
}
if (size)
{
c->data = ngx_palloc(size); // 在小块内存中开辟内存存储回调函数实参
if (c->data == nullptr)
{
return nullptr;
}
}
else
{
c->data = nullptr;
}
c->handler = nullptr;
c->next = pool->cleanup;
pool->cleanup = c;
return c;
}
// 小块内存分配
void * Ngx_mem_pool::ngx_palloc_small(size_t size, ngx_uint_t align)
{
u_char *m;
ngx_pool_s *p;
p = pool->current;
do {
m = p->d.last;
if (align)
{
m = ngx_align_ptr(m, NGX_ALIGNMENT);
}
if ((size_t)(p->d.end - m) >= size)
{
p->d.last = m + size;
return m;
}
p = p->d.next;
} while (p);
return ngx_palloc_block(size);
}
// 大块内存分配
void* Ngx_mem_pool::ngx_palloc_large(size_t size)
{
void *p;
ngx_uint_t n;
ngx_pool_large_s *large;
p = ngx_alloc(size);// 调用malloc开辟内存
if (p == nullptr)
{
return nullptr;
}
// 在大块内存头链表的前三个头部查看是否有空闲大块内存头部可用
n = 0;
for (large = pool->large; large != nullptr; large = large->next)
{
if (large->alloc == NULL)
{
large->alloc = p;
return p;
}
if (n++ > 3)
{
break;
}
}
// 在小块内存池中开辟大块内存头部
large = (ngx_pool_large_s*)ngx_palloc_small(sizeof(ngx_pool_large_s), 1);
if (large == nullptr)
{
free(p);
return nullptr;
}
large->alloc = p;
large->next = pool->large;
pool->large = large;
return p;
}
// 分配小块内存 内存块函数
void* Ngx_mem_pool::ngx_palloc_block(size_t size)
{
u_char *m;
size_t psize;
ngx_pool_s *p, *n;
// 获取第一个内存块大小
psize = (size_t)(pool->d.end - (u_char *)pool);
m = (u_char*)ngx_alloc(psize);// 开辟内存
if (m == nullptr)
{
return nullptr;
}
// 初始化新开辟内存的头信息
n = (ngx_pool_s* )m;
n->d.end = m + psize;
n->d.next = nullptr;
n->d.failed = 0;
m += sizeof(ngx_pool_data_s);
m = ngx_align_ptr(m, NGX_ALIGNMENT); // 进行内存对齐
n->d.last = m + size; // last指向开辟size后可用内存的起始地址
// 内存开辟失败,然后将failed++
for (p = pool->current; p->d.next != nullptr; p = p->d.next)
{
if (p->d.failed++ > 4)
{
pool->current = p->d.next;
}
}
p->d.next = n;
return m;
}
// 开辟内存函数,调用malloc
void* Ngx_mem_pool::ngx_alloc(size_t size)
{
void *p = malloc(size);
if (p == nullptr)
return nullptr;
return p;
}
测试代码
#include "ngx_mem_pool.h"
#include <iostream>
using namespace std;
struct Node
{
char*str;
FILE *file;
};
void func1(void * str)
{
free(str);
cout << "free str" << endl;
}
void func2(void *fd)
{
fclose((FILE*)fd);
cout << "close file" << endl;
}
int main()
{
Ngx_mem_pool mempool(512); //创建一个内存池
// 小块内存
int *q = (int*)mempool.ngx_palloc(20);
if (q == nullptr)
{
return -1;
}
// 大块内存
char *p = (char*)mempool.ngx_palloc(600);
if (p == nullptr)
{
return -1;
}
// 在小内存中开辟一个Node
Node* node = (Node*)mempool.ngx_palloc(sizeof(Node));
if (node == nullptr)
{
return -1;
}
node->str = (char*)malloc(20);
strcpy(node->str, "hello world Ngx!");
node->file = fopen("test.txt", "r");
if (node->file == nullptr)
{
return -1;
}
ngx_pool_cleanup_s* str = mempool.ngx_pool_cleanup_add(sizeof(ngx_pool_cleanup_s));
str->handler = func1;
str->data = node->str;
ngx_pool_cleanup_s*file = mempool.ngx_pool_cleanup_add(sizeof(ngx_pool_cleanup_s));
file->handler = func2;
file->data = node->file;
return 0;
}
测试代码可以通过单步调试,会看到内存池的实现!
其他修改注释等都在代码中有详细注释,新手上路,如有错误,请指出!!!
来源:CSDN
作者:皮卡丘~何
链接:https://blog.csdn.net/weixin_43604792/article/details/104401238