在C++11中实现Nginx中的内存池

在C++11中实现Nginx中的内存池

将Nginx中的内存池实现移植到c++,通过面向对象的方式实现

头文件:

//
// Created by 26685 on 2022-05-29 19:57.
// Description:NginxMemoryPool.h
//

#ifndef MEMORYPOOL_NGINXMEMORYPOOL_H
#define MEMORYPOOL_NGINXMEMORYPOOL_H

#include<cstdlib>
#include<cstdio>
#include<memory.h>


using u_char = unsigned char;
using ngx_uint_t = unsigned int;
using ngx_pool_cleanup_pt = void (*)(void *data);//函数指针ngx_pool_cleanup_pt

struct ngx_pool_s;

//清除节点
struct ngx_pool_cleanup_s {
    ngx_pool_cleanup_pt handler;//回调函数
    void *data;//上面函数中使用的数据
    ngx_pool_cleanup_s *next;
};

//指向下一个大尺寸pool的节点
struct ngx_pool_large_s {
    ngx_pool_large_s *next;//next指针,指向下一个节点
    void *alloc;//堆内存地址(大块内存地址)
};

//指向下一个小尺寸pool头结点的结构
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;
};
//将p调整为a的倍数
#define ngx_align_ptr(p, a)                                                   
    (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
//将d调整为a的倍数
#define ngx_align(d, a)     (((d) + (a - 1)) & ~(a - 1))

//将内存块设置为0
#define ngx_memzero(buf, n)       (void) memset(buf, 0, n)

#define  NGX_OK          0
#define  NGX_ERROR      -1
#define  NGX_AGAIN      -2
#define  NGX_BUSY       -3
#define  NGX_DONE       -4
#define  NGX_DECLINED   -5
#define  NGX_ABORT      -6

const int NGX_ALIGNMENT = sizeof(unsigned long);//对齐长度

const int ngx_pagesize = 4096;//最大页面大小4k

const int NGX_MAX_ALLOC_FROM_POOL = ngx_pagesize - 1;//最大小内存池

const int NGX_DEFAULT_POOL_SIZE = 16 * 1024;//

const int NGX_POOL_ALIGNMENT = 16;


const int NGX_MIN_POOL_SIZE = ngx_align((sizeof(ngx_pool_s) + 2 * sizeof(ngx_pool_large_s)), 
              NGX_POOL_ALIGNMENT);


class NginxMemoryPool {
public:

    explicit NginxMemoryPool(size_t size = 512);

    ~NginxMemoryPool() {
        printf("destroy pool! 
");
        ngx_destroy_pool();
    }

    void *ngx_create_pool(size_t size);

    void ngx_destroy_pool();

    void ngx_reset_pool();

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

    //不考虑内存对齐
    void *ngx_pnalloc(size_t size);

    void *ngx_pcalloc(size_t size);

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

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

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);
};


#endif //MEMORYPOOL_NGINXMEMORYPOOL_H

.cpp实现

//
// Created by 26685 on 2022-05-29 19:57.
// Description:NginxMemoryPool.cpp
//

#include "include/NginxMemoryPool.h"

ngx_pool_cleanup_s *NginxMemoryPool::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 *NginxMemoryPool::ngx_create_pool(size_t size) {
    ngx_pool_s *p;

    p = (ngx_pool_s *) malloc(size);//按照16字节对齐
    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;
}

void NginxMemoryPool::ngx_destroy_pool() {
    ngx_pool_s *p, *n;
    ngx_pool_large_s *l;
    ngx_pool_cleanup_s *c;

    //现根据内存池中的cleanup保存的信息把大块内存中指向的外部资源释放掉
    for (c = pool->cleanup; c; c = c->next) {
        if (c->handler) {
            c->handler(c->data);
        }
    }

    //清理掉外部资源后将大块内存释放掉
    for (l = pool->large; l; l = l->next) {//遍历每一个large内存
        if (l->alloc) {
            free(l->alloc);
        }
    }

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

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

void NginxMemoryPool::ngx_reset_pool() {
    ngx_pool_s *p;
    ngx_pool_large_s *l;

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

    //第一块内存的头是sizeof(ngx_pool_s)
    p->d.last = (u_char *) p + sizeof(ngx_pool_s);
    p->d.failed = 0;
    //后面内存块的头的大小是sizeof(ngx_pool_data_s)
    for (p = pool->d.next; p; 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;
}

void *NginxMemoryPool::ngx_palloc(size_t size) {
    if (size <= pool->max) {
        return ngx_palloc_small(size, 1);
    }
    return ngx_palloc_large(size);
}

void *NginxMemoryPool::ngx_pnalloc(size_t size) {
    if (size <= pool->max) {
        return ngx_palloc_small(size, 0);
    }
    return ngx_palloc_large(size);
}

void *NginxMemoryPool::ngx_pcalloc(size_t size) {
    void *p;

    p = ngx_palloc(size);
    if (p) {
        ngx_memzero(p, size);
    }

    return p;
}

int NginxMemoryPool::ngx_pfree(void *p) {
    ngx_pool_large_s *l;

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

            return NGX_OK;
        }
    }
    return NGX_DECLINED;
}

void *NginxMemoryPool::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 *NginxMemoryPool::ngx_palloc_block(size_t size) {
    u_char *m;
    size_t psize;
    ngx_pool_s *p, *newMem;

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

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

    newMem = (ngx_pool_s *) m;

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

    m += sizeof(ngx_pool_data_s);
    m = ngx_align_ptr(m, NGX_ALIGNMENT);
    newMem->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 = newMem;

    return m;
}

void *NginxMemoryPool::ngx_palloc_large(size_t size) {
    void *p;
    ngx_uint_t n;
    ngx_pool_large_s *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_s *) ngx_palloc_small(sizeof(ngx_pool_large_s), 1);//在小块池中建立large内存块
    if (large == nullptr) {
        free(p);
        return nullptr;
    }
    large->alloc = p;
    large->next = pool->large;
    pool->large = large;

    return p;
}

NginxMemoryPool::NginxMemoryPool(size_t size) {
    printf("%d
", size);
    ngx_create_pool(size);
}

测试代码:

#include <iostream>
#include <cstring>
#include "include/NginxMemoryPool.h"


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

void func1(void *p1) {
    char *p = (char *) p1;
    printf("free ptr mem!
");
    free(p);
}

void func2(void *pf1) {
    FILE *pf = (FILE *) pf1;
    printf("close file!
");
    fclose(pf);
}

int main() {
    NginxMemoryPool pool;

    // 512 - sizeof(ngx_pool_t) - 4095   =>   max
    //pool.ngx_create_pool(512);


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

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

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

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

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

    return 1;
}
hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » 在C++11中实现Nginx中的内存池