Nginx:移植Nginx内存池 | 附测试用例

ngx_mem_pool.h

#pragma once
#include<cstdlib>
#include<memory>

// 类型重命名
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;		// 所有的cleanup操作都被串在一条链表上
};

// 大块内存头部信息
using ngx_pool_large_t = struct ngx_pool_large_s;
struct ngx_pool_large_s {
	ngx_pool_large_s* next;		// 大块内存也被串在一条链表上
	void* alloc;				// 保存大块内存地址的起始位置
};

// 分配小块内存的内存池头部信息
using ngx_pool_t = struct ngx_pool_s;

struct ngx_pool_data_t {
	u_char* last;		// 可用小块内存的起始位置
	u_char* end;		// 末尾位置
	ngx_pool_t* next;	// 链表,连接下一个小块内存
	ngx_uint_t failed;	// 记录了当前小块内存分配失败的次数
};

// 内存池头部信息和管理成员信息
struct ngx_pool_s {
	ngx_pool_data_t       d;		// 当前小块内存的使用情况
	size_t                max;		// 小块内存和大块内存的分界线	
	ngx_pool_t* current;			// 指向第一个可提供小块内存分配的小块内存池
	ngx_pool_large_t* large;		// 指向大块内存的入口地址
	ngx_pool_cleanup_s* cleanup;	// 指向所有预置的清理操作(回调函数)的入口
};

// 把数值d调整成临近a的倍数
#define ngx_align(d, a)     (((d) + (a - 1)) & ~(a - 1))
// 把指针p调整成a临近的倍数
#define ngx_align_ptr(p, a)                                                   \
    (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
// 特定平台 小块内存分配考虑字节对齐时的单位
#define NGX_ALIGNMENT   sizeof(unsigned long)    /* platform word */
// 将指定内存置为0
#define ngx_memzero(buf, n)       (void) memset(buf, 0, n)
// free()
#define ngx_free free

/*
移植Nginx内存池的代码
*/

/*
 * NGX_MAX_ALLOC_FROM_POOL should be (ngx_pagesize - 1), i.e. 4095 on x86.
 * On Windows NT it decreases a number of locked pages in a kernel.
 */
// 默认一个物理页面的大小4K
const int ngx_pagesize = 4096;
// 小块内存池可分配的最大空间
const int NGX_MAX_ALLOC_FROM_POOL = ngx_pagesize - 1;
// 默认内存池的大小
const int NGX_DEFAULT_POOL_SIZE = 16 * 1024;
// 内存池按照16个字节对齐
const int NGX_POOL_ALIGNMENT = 16;

// ngx小块内存池最小的size调整成NGX_POOL_ALIGNMENT邻近的倍数
const int NGX_MIN_POOL_SIZE = ngx_align((sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t)), NGX_POOL_ALIGNMENT);

class ngx_mem_pool
{
public:

	// 创建指定size大小的内存池(小块内存不超过一个页面4095)
	void* ngx_create_pool(size_t size);

	// 考虑内存对齐,从内存池申请size大小
	void* ngx_palloc(size_t size);

	// 和上面一样,但不考虑内存对齐
	void* ngx_pnalloc(size_t size);

	// 调用的是ngx_palloc(),但会初始化为0
	void* ngx_pcalloc(size_t size);

	// 释放大块内存
	void ngx_pfree(void* p);

	// 内存重置函数
	void ngx_reset_pool();

	// 内存池销毁函数
	void ngx_destroy_pool();

	// 添加回调清理操作函数
	ngx_pool_cleanup_s* ngx_pool_cleanup_add(size_t size);

private:
	ngx_pool_s* pool;

	// 小块内存分配
	void* ngx_palloc_small(size_t size, ngx_uint_t align);
	// 分配新的小块内存池
	void* ngx_palloc_block(size_t size);
	// 大块内存分配
	void* ngx_palloc_large(size_t size);

};

ngx_mem_pool.cpp

创建内存池和销毁内存池可以放在内存池的构造函数和析构函数中,这里没有放,所以在创建过程中把地址赋给内存池成员pool。

#include "ngx_mem_pool.h"

// 创建内存池
void* ngx_mem_pool::ngx_create_pool(size_t size)
{
    ngx_pool_s* p;

    p = (ngx_pool_s*)malloc(size);
    if (p == nullptr) {
        return nullptr;
    }

    p->d.last = (u_char*)p + sizeof(ngx_pool_s);
    p->d.end = (u_char*)p + size;
    p->d.next = nullptr;
    p->d.failed = 0;

    size = size - sizeof(ngx_pool_s);
    p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;

    p->current = p;

    p->large = nullptr;
    p->cleanup = nullptr;

    // 赋值给我的成员变量
    pool = p;

    return p;
}

// 考虑内存对齐,从内存池申请size大小
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) {
        ngx_memzero(p, size);
    }

    return p;
}

// 小块内存分配
void* ngx_mem_pool::ngx_palloc_small(size_t size, ngx_uint_t align)
{
    u_char* m;
    ngx_pool_t* 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_block(size_t size)
{
    u_char* m;
    size_t       psize;
    ngx_pool_t* p, * new_pool;

    psize = (size_t)(pool->d.end - (u_char*)pool);

    m = (u_char*)malloc(psize);
    if (m == nullptr) {
        return nullptr;
    }

    new_pool = (ngx_pool_s*)m;

    new_pool->d.end = m + psize;
    new_pool->d.next = nullptr;
    new_pool->d.failed = 0;

    m += sizeof(ngx_pool_data_t);
    m = ngx_align_ptr(m, NGX_ALIGNMENT);
    new_pool->d.last = m + size;

    for (p = pool->current; p->d.next; p = p->d.next) {
        if (p->d.failed++ > 4) {
            pool->current = p->d.next;
        }
    }

    p->d.next = new_pool;

    return m;
}

// 大块内存分配
void* ngx_mem_pool::ngx_palloc_large(size_t size)
{
    void* p;
    ngx_uint_t         n;
    ngx_pool_large_t* large;

    p = malloc(size);
    if (p == nullptr) {
        return nullptr;
    }

    n = 0;
    for (large = pool->large; large; large = large->next) {
        if (large->alloc == nullptr) {
            large->alloc = p;
            return p;
        }

        if (n++ > 3) {
            break;
        }
    }

    large = (ngx_pool_large_t*)ngx_palloc_small( sizeof(ngx_pool_large_s), 1);
    if (large == nullptr) {
        ngx_free(p);
        return nullptr;
    }

    large->alloc = p;
    large->next = pool->large;
    pool->large = large;

    return p;
}

// 释放大块内存
void ngx_mem_pool::ngx_pfree(void* p)
{
    ngx_pool_large_t* l;

    for (l = pool->large; l; l = l->next) {
        if (p == l->alloc) {
            ngx_free(l->alloc);
            l->alloc = nullptr;

            return;
        }
    }
}

// 内存重置函数
void ngx_mem_pool::ngx_reset_pool()
{
    ngx_pool_t* p;
    ngx_pool_large_t* l;

    // 大块内存的释放
    for (l = pool->large; l; l = l->next) {
        if (l->alloc) {
            ngx_free(l->alloc);
        }
    }

    // the first block
    p = pool;
    p->d.last = (u_char*)p + sizeof(ngx_pool_t);
    p->d.failed = 0;

    // remaining memory pool
    for (p = p->d.next; p; p = p->d.next) {
        p->d.last = (u_char*)p + sizeof(ngx_pool_data_t);
        p->d.failed = 0;
    }

    pool->current = pool;
    pool->large = nullptr;
}

// 内存池销毁函数
void ngx_mem_pool::ngx_destroy_pool()
{
    ngx_pool_t* p, * n;
    ngx_pool_large_t* l;
    ngx_pool_cleanup_s* c;

    for (c = pool->cleanup; c; c = c->next) {
        if (c->handler) {
            c->handler(c->data);
        }
    }

    for (l = pool->large; l; l = l->next) {
        if (l->alloc) {
            ngx_free(l->alloc);
        }
    }

    for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
        ngx_free(p);

        if (n == nullptr) {
            break;
        }
    }
}

// 添加回调清理操作函数
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;
}

ngx_test_pool.cpp

#define _CRT_SECURE_NO_WARNINGS
#include "ngx_mem_pool.h"
#include <iostream>
#include<cstring>
using namespace std;

typedef struct Data stData;
struct Data
{
    char* ptr;
    FILE* pfile;
};

void func1(void* p1) // void (*)(void*)
{
    char* p = (char*)p1;
    cout << "free ptr mem!" << endl;
    delete p;
}
void func2(void* pf1)
{
    FILE* pf = (FILE*)pf1;
    cout << "close file!" << endl;
    fclose(pf);
}

int main(void)
{
    ngx_mem_pool mempool;
    // 512 - sizeof(ngx_pool_t) - 4095   =>   max
    if (nullptr == mempool.ngx_create_pool(512))
    {
        cout << "ngx_create_pool fail..." << endl;
        return -1;
    }

    void* p1 = mempool.ngx_palloc(128); // 从小块内存池分配的
    if (nullptr == p1)
    {
        cout << "ngx_palloc 128 bytes fail..." << endl;
        return -1;
    }

    stData* p2 = (stData*)mempool.ngx_palloc(512); // 从大块内存池分配的
    if (nullptr == p2)
    {
        cout << "ngx_palloc 512 bytes fail..." << endl;
        return -1;
    }
    p2->ptr = (char*)malloc(12);
    strcpy(p2->ptr, "hello world");
    p2->pfile = fopen("data.txt", "w");

    ngx_pool_cleanup_s* c1 = mempool.ngx_pool_cleanup_add(sizeof(char*));
    c1->handler = func1;
    c1->data = p2->ptr;

    ngx_pool_cleanup_s* c2 = mempool.ngx_pool_cleanup_add(sizeof(FILE*));
    c2->handler = func2;
    c2->data = p2->pfile;

    mempool.ngx_destroy_pool(); // 1.调用所有的预置的清理函数 2.释放大块内存 3.释放小块内存池所有内存

    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_索伦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值