草庐IT

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

woden3702 2023-03-28 原文

将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! \n");
        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\n", 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!\n");
    free(p);
}

void func2(void *pf1) {
    FILE *pf = (FILE *) pf1;
    printf("close file!\n");
    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\n");
    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;
}

有关在C++11中实现Nginx中的内存池的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  3. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  4. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  5. ruby - 在 Ruby 中实现 `call_user_func_array` - 2

    我怎样才能完成http://php.net/manual/en/function.call-user-func-array.php在ruby中?所以我可以这样做:classAppdeffoo(a,b)putsa+benddefbarargs=[1,2]App.send(:foo,args)#doesn'tworkApp.send(:foo,args[0],args[1])#doeswork,butdoesnotscaleendend 最佳答案 尝试分解数组App.send(:foo,*args)

  6. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  7. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  8. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  9. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  10. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

随机推荐