• NGINX(二)内存池


    ngxin中为了加快内存分配的速度,引入了内存池, 大块申请, 减少分配次数, 小块分割, 极大的提高了内存申请速度, 另外一个用途就是省去了很多内存管理的任务,因为这里没有提供内存释放的功能,也就是说在pool中分配的内存,只有pool被销毁的时候才能释放掉,真正的还给系统, 因此全局的pool存储的都是一些静态的不会变动的数据, 而会变动的数据都会单独创建一个pool, 用完之后释放掉pool, 也就实现了集中申请集中释放, 肯定会有浪费内存的现象存在, 和提高运行速度比起来, 浪费点内存还是可以接受的.

    基本数据结构

    typedef struct ngx_pool_cleanup_s  ngx_pool_cleanup_t;
    typedef struct ngx_pool_large_s    ngx_pool_large_t;
    typedef struct ngx_pool_s          ngx_pool_t;
    
    struct ngx_pool_cleanup_s {
    	ngx_pool_cleanup_pt   handler;
    	void                 *data;
    	ngx_pool_cleanup_t   *next;
    };
    
    struct ngx_pool_large_s {
    	ngx_pool_large_t     *next;
    	void                 *alloc;
    };
    
    typedef struct {
    	/*使用的内存位置*/
    	u_char               *last;
    	/*分配总的内存结束位置*/
    	u_char               *end;
    	/*下一块内存指针*/
    	ngx_pool_t           *next;
    	/*标记分配失败次数*/
    	ngx_uint_t           failed;
    } ngx_pool_data_t;
    
    struct ngx_pool_s {
    	/*内存池中内存空间*/
    	ngx_pool_data_t       d;
    	/*最大内存限定*/
    	size_t                max;
    	/*当前内存池分配内存位置*/
    	ngx_pool_t           *current;
    	/*缓存chain链表, 重新申请时从这里直接取出*/
    	ngx_chain_t          *chain;
    	/*大块内存链表, 很简单直接分配内存, 挂接到链表结束为止*/
    	ngx_pool_large_t     *large;
    	ngx_pool_cleanup_t   *cleanup;
    	ngx_log_t            *log;
    };
    

    创建内存池

    创建一块内存池, 首先会申请一块用户指定的大小, 即size大小, 但是size很显然最小要为sizeof(ngx_pool_t)大小, 申请内存开头放置ngx_pool_t结构体, 剩余的用作内存池内存, 提供给用户使用, 如下图示

    |----------------> size <--------------------|
    |-----------------|--------------------------|
    p   ngx_pool_t    p->d.last                  p->d.end
    
    ngx_pool_t *
    ngx_create_pool(size_t size, ngx_log_t *log)
    {
    	ngx_pool_t  *p;
    
    	/*申请size大小内存*/
    	p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);
    	if (p == NULL) {
    		return NULL;
    	}
    	
    	/*用户使用内存要除去sizeof(ngx_pool_t)大小*/
    	p->d.last = (u_char *) p + sizeof(ngx_pool_t);
    	/*设置分配内存结束位置*/
    	p->d.end = (u_char *) p + size;
    	p->d.next = NULL;
    	p->d.failed = 0;
    
    	size = size - sizeof(ngx_pool_t);
    	p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;
    	
    	/*设置当前使用的pool为p,因为就一个*/
    	p->current = p;
    	p->chain = NULL;
    	p->large = NULL;
    	p->cleanup = NULL;
    	p->log = log;
    
    	return p;
    }
    

    申请内存

    分配带内存对齐的内存, 一般用于结构体, 加快访问速度.

    void *
    ngx_palloc(ngx_pool_t *pool, size_t size)
    {
    	u_char      *m;
    	ngx_pool_t  *p;
    	
    	/*size大小决定进行小块内存分配还是大块内存分配方案*/
    	if (size <= pool->max) {
    	
    		/*取出当前pool*/
    		p = pool->current;
    
    		do {
    			m = ngx_align_ptr(p->d.last, 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(pool, size);
    	}
    	
    	return ngx_palloc_large(pool, size);
    }
    

    分配原生大小内存, 一般字符串, 一整块内存的时候使用.

    void *
    ngx_pnalloc(ngx_pool_t *pool, size_t size)
    {
    	u_char      *m;
    	ngx_pool_t  *p;
    
    	if (size <= pool->max) {
    
    		p = pool->current;
    
    		do {
    			m = p->d.last;
    
    			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(pool, size);
    	}
    
    	return ngx_palloc_large(pool, size);
    }
    

    重新分配一个pool

    static void *
    ngx_palloc_block(ngx_pool_t *pool, size_t size)
    {
    	u_char      *m;
    	size_t       psize;
    	ngx_pool_t  *p, *new, *current;
    	
    	/*内存大小和第一次用户指定的大小一致*/
    	psize = (size_t) (pool->d.end - (u_char *) pool);
    
    	m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);
    	if (m == NULL) {
    		return NULL;
    	}
    
    	new = (ngx_pool_t *) m;
    	
    	new->d.end = m + psize;
    	new->d.next = NULL;
    	new->d.failed = 0;
    	
    	/*由于只使用了ngx_pool_data_t数据结构, 因此这里实际可使用的内存只去除了sizeof(ngx_pool_data_t)大小, 跟创建时sizeof(ngx_pool_t)不同*/
    	m += sizeof(ngx_pool_data_t);
    	m = ngx_align_ptr(m, NGX_ALIGNMENT);
    	new->d.last = m + size;
    
    	current = pool->current;
    	
    	/*遍历链表最后位置, 但current并不一定到最后, current从分配失败次数少于三次位置开始, 目的是减少分配时遍历的次数*/
    	for (p = current; p->d.next; p = p->d.next) {
    		if (p->d.failed++ > 4) {
    			current = p->d.next;
    		}
    	}
    	
    	/*最新分配的内存放置到链表末尾*/
    	p->d.next = new;
    
    	pool->current = current ? current : new;
    
    	return m;
    }
    

    关于大块内存申请是直接向系统申请, 释放的时候直接返回给系统, 没有什么好讲的.

  • 相关阅读:
    Lucene 入门实战
    ActiveMQ 入门实战(3)--SpringBoot 整合 ActiveMQ
    ActiveMQ 入门实战(2)--Java 操作 ActiveMQ
    Hdevelop(Halcon)快捷键
    2021年9月3日第7次刷第一章。但行好事莫问前程
    大家好。我准备第6次从第一章重新往回写了。
    ODOO13之十四 :Odoo 13开发之部署和维护生产实例
    Odoo 13之十三 :开发之创建网站前端功能
    ODOO13之12:Odoo 13开发之报表和服务端 QWeb
    doo 13 之11 :开发之看板视图和用户端 QWeb
  • 原文地址:https://www.cnblogs.com/ourroad/p/4838362.html
Copyright © 2020-2023  润新知