Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【Nginx 源码学习】内存池 及 优秀案例赏析:Nginx内存池设计

【Nginx 源码学习】内存池 及 优秀案例赏析:Nginx内存池设计

作者头像
看、未来
发布于 2022-01-10 01:59:32
发布于 2022-01-10 01:59:32
98201
代码可运行
举报
运行总次数:1
代码可运行

文章目录

关于设计内存池之我的想法

1、首先,你的开发环境允许你写内存池。(不要跟我说你拿着Python来写个内存池哈) 2、其次,多学学开源的/不开源的优秀线程池源码设计,人家是经过千锤百炼的。比如GNU、nginx、STL等。 3、使用内存池的其中一个优点在于确定性高,这对于时间要去苛刻的实时系统来说至关重要。比方说股票系统。 4、malloc是一个通用的内存分配器。就看你怎么理解这三个字了。 5、针对特殊场景甚至可以为重要的线程单独开内存池。 6、内存池可以节省内存,提高缓存命中率。当然,你要是觉得不需要那就不需要咯。

内存池案例

作者:阿哲 链接:https://www.zhihu.com/question/21894104/answer/19693701 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

再大的内存,只要软件运行的时间足够久,都有可能产生大量的内存碎片,从而对性能和可用内存造成负面影响。 造成内存碎片的原因大致可以归为两类:

  1. 内存分配机制。拥有先进GC机制的语言(如Java、C#),在对抗内存碎片方面表现较好。它们的GC一般会有个Compact步骤,会移动对象在内存中的位置,将多个对象整齐无间隙地排列好,从而消除了不少内存碎片。
  2. 如果是使用传统malloc/free或者自己写内存分配的话,产生内存碎片的概率不小。这方面比较典型的例子就是Firefox,它以前代码里有不少自己写的allocator,内存碎片问题是非常严重的。后来Mozilla开始逐步采用jemalloc来帮助解决这个问题。

举2个例子:Firefox7的时候修改了一个内存分配行为,就一下子降低了不少内存碎片:Firefox 7 Might Solve Memory Fragmentation IssuesFirefox15的时候对addon的机制做了改动,一下子解决了大量长期困扰的addon内存问题:Firefox 15 plugs the add-on leaks

取决于软件的具体类型,对抗内存碎片可能是个长期的战争,有兴趣的可以翻翻Mozilla的MemShrink项目:MemShrink | Nicholas Nethercote 看看别人是怎么用了2年功夫把Firefox从一个超级耗内存的浏览器变成一个最节约内存的浏览器。

malloc 底层原理

  1. malloc开始搜索空闲内存块,如果能找到一块大小合适的就分配出去
  2. 如果malloc找不到一块合适的空闲内存,那么调用brk等系统调用扩大堆区从而获得更多的空闲内存
  3. malloc调用brk后开始转入内核态,此时操作系统中的虚拟地址系统开始工作,扩大进程的堆区,操作系统并没有为此分配真正的物理内存
  4. brk执行结束后返回到malloc,从内核态切换到用户态,malloc找到一块合适的空闲内存后返回
  5. 进程拿到内存,继续干活。
  6. 当有代码读写新申请的内存时系统内部出现缺页中断,此时再次由用户态切换到内核态,操作系统此时真正的分配物理内存,之后再次由内核态切换回用户态,程序继续。

如果对堆和栈有所了解的朋友应该会知道,堆是像上伸展的,栈是向下延伸的,那什么向上向下啊?有点迷哈。看个图:

一切尽在不言中咯。


jemalloc && tcmalloc

jemalloc

tcmalloc

说实话啊,这俩我都没有用过呢,也是第一次听,先把概念放这儿,之后有时间了研究研究。

Nginx内存池设计

Nginx 使用内存池对内存进行管理,把内存分配归结为大内存分配和小内存分配,申请的内存大小比同页的内存池最大值 max 还 大,则是大内存分配,否则为小内存分配。

  1. 大块内存的分配请求不会直接在内存池上分配内存来满足请求,而是直接向系统申请一块内存(就像 直接使用 malloc 分配内存一样),然后将这块内存挂到内存池头部的 large 字段下。
  2. 小块内存分配,则是从已有的内存池数据区中分配出一部分内存。

Nginx 内存分配总流图如下:其中 size 是用户请求分配内存的大小,pool是现有内存池。

基础数据结构

数据块:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typedef struct {
	u_char *last; // 当前内存池分配到此处,即下一次分配从此处开始
	u_char *end; // 内存池结束位置
	ngx_pool_t *next; // 内存池里面有很多块内存,这些内存块就是通过该指针连成链表的
	ngx_uint_t failed; // 内存池分配失败次数
} ngx_pool_data_t;

池结构:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct ngx_pool_s {
	ngx_pool_data_t d; // 指向内存池的第一个数据块
	size_t max; // 内存池数据块的最大值(数目)
	ngx_pool_t *current; // 指向当前内存池
	ngx_chain_t *chain; // 该指针挂接一个ngx_chain_t结构
	ngx_pool_large_t *large; // 大块内存链表,即分配空间超过max的内存
	ngx_pool_cleanup_t *cleanup; // 释放内存池的callback
	ngx_log_t *log; // 主要用于记录日志信息
};

大块内存:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct ngx_pool_large_s {
	ngx_pool_large_t *next; // 指向下一个large内存
	void *alloc; // 指向分配的large内存
};

回收站:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct ngx_pool_cleanup_s {
	ngx_pool_cleanup_pt handler; // 指向用于cleanup本cleanup内存
	void *data; // 指向分配的cleanup内存
	ngx_pool_cleanup_t *next; // 指向下一个cleanup内存
};

ngx_pool_t 的逻辑结构:

源码分析

ngx_create_pool 创建内存池

用于创建一个内存池,我们创建时,传入我们的初始大小:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#define ngx_memalign(alignment, size, log)  ngx_alloc(size, log)
//ngx_alloc:对malloc进行了简单封装

ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log)
{
	ngx_pool_t *p;
	p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);
	if (p == NULL) {
		return NULL;
	}
	// 可以看到 last 指向 pool 之后的位置,即下一个pool块分配的位置
	p->d.last = (u_char *) p + sizeof(ngx_pool_t);
	// end 指向pool的size的最后,即当前pool可容纳的最大尺寸的结束位置
	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;
	/*
		nginx对内存的管理分为大内存与小内存,
		当某一个申请的内存大于某一个值时,就需要从大内存中分配空间,否则从小内存中分配空间。
		nginx中的内存池是在创建的时候就设定好了大小,
		在以后分配小块内存的时候,如果内存不够,则是重新创建一块内存串到内存池中,而不是将原有的内存池进行扩张。
		当要分配大块内存时,则是在内存池外面再分配空间进行管理的,称为大块内存池。
	*/
	p->current = p;
	p->chain = NULL;
	p->large = NULL;
	p->cleanup = NULL;
	p->log = log;
	return p;
}

ngx_destroy_pool 销毁内存池

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void ngx_destroy_pool(ngx_pool_t *pool)
{
	ngx_pool_t *p, *n;
	ngx_pool_large_t *l;
	ngx_pool_cleanup_t *c;
	
	for (c = pool->cleanup; c; c = c->next) {
		if (c->handler) {
			ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
			"run cleanup: %p", c);
			c->handler(c->data);
		}
	}
	
	for (l = pool->large; l; l = l->next) {
		ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc);
		
		if (l->alloc) {
			ngx_free(l->alloc);
		}
	}
	
	#if (NGX_DEBUG)
	… …
	#endif
	
	for (p = pool, n = pool->d.next; ; p = n, n = n->d.next) {
		ngx_free(p);
		
		if (n == NULL) {
			break;
		}
	}
}

遍历内存池链表,释放所有内存,包括pool,large,cleanup链表,如果指定了cleanup回调来释放,则调用cleanup的handler来释放cleanup链表中的内存。

先依次释放pool中cleanup,large类型的链表,最后释放pool本身的链表。

ngx_reset_pool 重置内存池

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void ngx_reset_pool(ngx_pool_t *pool)
{
	ngx_pool_t *p;
	ngx_pool_large_t *l;
	
	// 先遍历large链表,释放large内存
	for (l = pool->large; l; l = l->next) {
		if (l->alloc) {
			ngx_free(l->alloc);
		}
	}
	
	pool->large = NULL;
	
	//重置所有小块内存区
	for (p = pool; p; p = p->d.next) {
		p->d.last = (u_char *) p + sizeof(ngx_pool_t);
	}
}

ngx_palloc 分配内存

ngx_align_ptr:一个用来内存地址取整的宏。取整可以降低CPU读取内存的次数,提高性能。这里并没有真正意义调用malloc等函数申请内存,而是移动指针标记而已,所以内存对齐的活,得自己动手。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#define ngx_align_ptr(p, a)                                                   \
    (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void *ngx_palloc(ngx_pool_t *pool, size_t size)
{
	u_char *m;
	ngx_pool_t *p;
	
	if (size <= pool->max) { // 如果需要分配的size大于max,则使用palloc_large来分配
		p = pool->current; // 小于max,则从current开始遍历pool链表
		do {
			// 每次从last处开始分配aligned内存
			m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT);
			
			if ((size_t) (p->d.end - m) >= size) {
				// 如果分配的内存够用,则就从此处分配,并调整last
				p->d.last = m + size;
				return m;
			}
			
			p = p->d.next;
		} while (p);
		// 表示链表里没有能够分配size大小的内存节点
		// 则生成一个新的节点,并在其中分配内存
		return ngx_palloc_block(pool, size);
	}
	// 大于max的,就在large中进行分配
	return ngx_palloc_large(pool, size);
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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;//设置新内存块的end
	new->d.next = NULL;
	new->d.failed = 0;

	m += sizeof(ngx_pool_data_t);//将指针m移动到d后面的一个位置,作为起始位置
	m = ngx_align_ptr(m, NGX_ALIGNMENT);//对m指针按4字节对齐处理
	new->d.last = m + size;//设置新内存块的last,即申请使用size大小的内存

	current = pool->current;
  //这里的循环用来找最后一个链表节点,这里failed用来控制循环的长度,如果分配失败次数达到5次,
  //就忽略,不需要每次都从头找起
	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;
}

ngx_palloc_large:开辟一个大内存检查后交给大内存链表管理。所以开辟的内存必定在大内存链表上。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
 * 1)判断pool->large链表上查询是否有NULL的,只在链表上往下查询3次,主要判断大数据块是否有被释放的,有就给它赋值,如果没有则只能跳出。
 * 2)然后往下新创建一个pool->large结构体,将刚开辟的空间赋给该新结构体管理。
*/

static void *ngx_palloc_large(ngx_pool_t *pool, size_t size)
{
    void              *p;
    ngx_uint_t         n;
    ngx_pool_large_t  *large;

    p = ngx_alloc(size, pool->log);//注意该函数是单独调用malloc,所以它的内存与内存池链表的内存是不连续的或者叫无关。
    if (p == NULL) {
        return NULL;
    }

    n = 0;

	// 1)判断pool->large链表上查询是否有NULL的,只在链表上往下查询3次,主要判断大数据块是否有被释放的,有就给它赋值,如果没有则只能跳出
    for (large = pool->large; large; large = large->next) {
        if (large->alloc == NULL) {
            large->alloc = p;
            return p;
        }

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

	// 2)新建pool->large结构体管理新内存,注意:是创建结构体的大小,属于小内存块(不要以为调用ngx_palloc_small后会造成递归调用)
    large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);
    if (large == NULL) {
        ngx_free(p);
        return NULL;
    }

    large->alloc = p;//刚开辟的内存交给pool->large链表管理
    large->next = pool->large;//插入新的pool->large结构体。注:插法是每次新的pool->large结构体插进第一个pool->large的后面。即pool->large->la3->la2->la1->NULL
    pool->large = large;

    return p;
}

ngx_pfree 内存清理

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 指定释放大内存块链表的某一块大内存。
 * 这里可以看到大内存的管理是支持释放某一块大内存的,所以上面的ngx_palloc_large函数每一次都检查前三个是否为空,
 * 确保前三个有内存空间可用,至于后面是否为空就只能不怎么关心了。
 */
ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p)
{
    ngx_pool_large_t  *l;

	//遍历大内存链表,若找到想要释放的大内存则释放,否则返回错误NGX_DECLINED
    for (l = pool->large; l; l = l->next) {
        if (p == l->alloc) {
            ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
                           "free: %p", l->alloc);
            ngx_free(l->alloc);
            l->alloc = NULL;

            return NGX_OK;
        }
    }

    return NGX_DECLINED;
}

cleanup机制

pool->cleanup本身是一个链表,每个ngx_pool_cleanup_t的数据结构上,保存着内存数据的本身cleanup->data和回调清理函数cleanup->handler。

ngx_pool_cleanup_add:分配一个可以用于回调函数清理内存块的内存。内存块仍旧在p->d或p->large上(因为调用的是ngx_palloc)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 1)创建一个新的ngx_pool_cleanup_t结构体并给其内部成员开辟内存空间。
 * 2)使用头插法将新的结构体插入清理链表。
 * 
 * 注意:初始化时回调c->handler设为NULL,并且返回值为返回当前结构体,所以该内存可以由用户自定义并且自行处理,非常灵活。
 * 
 * 实际上该函数注意是用来添加以下两个内容:
 * 1. 文件描述符
 * 2. 外部自定义回调函数可以来清理内存
 */
 */
ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)
{
    ngx_pool_cleanup_t  *c;

	// 1)创建新的清理结构体和开辟空间
    c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t));
    if (c == NULL) {
        return NULL;
    }

    if (size) {
        c->data = ngx_palloc(p, size);//该函数调用samll或者large,所以内存块仍旧在p->d或p->large上
        if (c->data == NULL) {
            return NULL;
        }
    } else {
        c->data = NULL;
    }

	// 2)使用头插法插入清理链表,并且回调设为NULL等待用户设置。
    c->handler = NULL;
    c->next = p->cleanup;

    p->cleanup = c;

    ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, p->log, 0, "add cleanup: %p", c);

    return c;
}

ngx_pool_run_cleanup_file:清除p->cleanup链表上的某个已打开的文件描述符fd占用的内存块(或者叫清除指定的文件描述符)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd) {
	ngx_pool_cleanup_t *c;
	ngx_pool_cleanup_file_t *cf;
 
 	// 遍历清理链表
	for (c = p->cleanup; c; c = c->next) {
		if (c->handler == ngx_pool_cleanup_file) {
 
			cf = c->data;//因为为清理文件描述符,此时的c->data应为ngx_pool_cleanup_file_t的结构体类型
 			
 			// 判断是否是指定要删除的fd
			if (cf->fd == fd) {
				c->handler(cf); /* 调用ngx_pool_cleanup_file回调函数清理指定内存cf */
				c->handler = NULL;
				return;
			}
		}
	}
}

ngx_pool_cleanup_file:ngx_pool_run_cleanup_file的回调函数。通过ngx_close_file里面去调用底层的close关闭掉对应的文件描述符。 ngx官方写的回调函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void ngx_pool_cleanup_file(void *data) {
	ngx_pool_cleanup_file_t *c = data;
 
	ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d",
			c->fd);
 
	if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {
		ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
				ngx_close_file_n " \"%s\" failed", c->name);
	}
}

ngx_pool_delete_file:这里是删除文件的回调函数,是连文件也删除。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
 * #define ngx_delete_file(name)    unlink((const char *) name)
 * #define ngx_close_file           close
 * 
 * 该函数调用了ngx_delete_file和ngx_close_file进行删除文件。
 * 1)调用了ngx_delete_file宏,而该宏调用底层的unlink删除文件。
 * 2)调用了ngx_close_file宏,而该宏调用底层的close删除文件
 * 
*/
void ngx_pool_delete_file(void *data)
{
    ngx_pool_cleanup_file_t  *c = data;

    ngx_err_t  err;

    ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d %s",
                   c->fd, c->name);

    if (ngx_delete_file(c->name) == NGX_FILE_ERROR) {
        err = ngx_errno;

        if (err != NGX_ENOENT) {
            ngx_log_error(NGX_LOG_CRIT, c->log, err,
                          ngx_delete_file_n " \"%s\" failed", c->name);
        }
    }

    if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
                      ngx_close_file_n " \"%s\" failed", c->name);
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022/01/04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Nginx源码剖析之内存池,与内存管理
    Nginx(发音同 engine x)是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行。由俄罗斯的程序设计师Igor Sysoev所开发,最初供俄国大型的入口网站及搜寻引擎Rambler(俄文:Рамблер)使用。  
bear_fish
2018/09/14
1.1K0
Nginx源码剖析之内存池,与内存管理
初识nginx——内存池篇
初识nginx——内存池篇      为了自身使用的方便,Nginx封装了很多有用的数据结构,比如ngx_str_t ,ngx_array_t, ngx_pool_t 等等,对于内存池,nginx设计的十分精炼,值得我们学习,本文介绍内存池基本知识,nginx内存池的结构和关键代码,并用一个实际的代码例子作了进一步的讲解 一、内存池概述     内存池是在真正使用内存之前,预先申请分配一定数量的、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够用时,再继
magicsoar
2018/02/06
1.6K0
初识nginx——内存池篇
【C】高并发内存池设计
高并发内存池设计 高并发下传统方式的弊端 在传统C语言中,我们使用malloc、calloc、realloc、free来进行内存的申请分配与释放,函数原型如下。C++中则是new、delete。 void *malloc(size_t size); malloc在内存的动态存储区中分配了一块长度为size字节的连续区域返回该区域的首地址。 void *calloc(size_t nmemb, size_t size); 与malloc相似,参数size为申请地址的单位元素长度,nmem
半生瓜的blog
2023/05/13
1K0
【C】高并发内存池设计
Nginx内存池
nginx里内存的使用大都十分有特色:申请了永久保存,抑或伴随着请求的结束而全部释放,还有写满了缓冲再从头接着写.这么做的原因也主要取决于Web Server的特殊的场景,内存的分配和请求相关,一条请求处理完毕,即可释放其相关的内存池,降低了开发中对内存资源管理的复杂度,也减少了内存碎片的存在.
后端技术探索
2019/05/07
1.3K0
探索Nginx:深入理解Nginx基础组件的使用
Nginx自己实现了一个内存池组件。Nginx作为服务器,当客户端 TCP连接 &HTTP请求 到来时,Nginx会为该连接创建一个专属的内存池;这个内存池的生命周期是连接建立时创建,连接断开时销毁。客户端和Nginx通信的所有数据和操作(HTTP协议解析、HTTP数据解析等)都在内存池中完成。
Lion 莱恩呀
2025/01/05
3350
探索Nginx:深入理解Nginx基础组件的使用
一文浅析内存管理机制
众所周知,程序需要加载到物理内存才能运行,多核时代会出现多个进程同时操作同一物理地址的情况,进而造成混乱和程序崩溃。计算机当中很多问题的解决都是通过引入中间层,为解决物理内存使用问题,虚拟内存作为中间层进入了操作系统,从此,程序不在直接操作物理内存,只能看到虚拟内存,通过虚拟内存,非常优雅的将进程环境隔离开来,每个进程都拥有自己独立的虚拟地址空间,且所有进程地址空间范围完全一致,也给编程带来了很大的便利,同时也提高了物理内存的使用率,可同时运行更多的进程。
范蠡
2021/04/08
1.4K0
一文浅析内存管理机制
Nginx(10):数据类型 与 数据结构之 ngx_array
ngx_str_t的data成员指向的并不是普通的字符串,因为这段字符串未必会以’\0’作 为结尾,所以使用时必须根据长度len来使用data成员。
看、未来
2021/10/09
3240
Nginx(10):数据类型 与 数据结构之 ngx_array
Nginx(12):Buffer缓冲区设计
刚那个长得像deque的链表需要找它的应用场景,缓冲区就不用我多说了吧,前前后后也看了好几个缓冲区的实现,谁的好,就拿来用咯。
看、未来
2021/10/09
8340
Nginx(12):Buffer缓冲区设计
【Nginx 源码学习】动态数组
1、Nginx的数组只存储比较小的数据 2、数组的元素长度在创建数组的时候就固定死了。但是数组个数,会自动扩容。 3、数组的数据结构和元素内存都会分配在Nginx的pool内存池上。 4、数组回收会去检查pool内存池,看是否可以将数组内存交还给内存池。
看、未来
2022/01/10
5990
【Nginx 源码学习】动态数组
超越内存限制:深入探索内存池的工作原理与实现
为什么需要内存池? 在系统应用层面,程序开发使用的都是虚拟内存。物理内存是底层的,只有底层程序(比如驱动、固件等)可以接触到。
Lion 莱恩呀
2024/09/25
2870
超越内存限制:深入探索内存池的工作原理与实现
手把手带你用C/C++实现一个内存池(图文结合)
为什么要用内存池?首先,在7 * 24h的服务器中如果不使用内存池,而使用malloc和free,那么就非常容易产生内存碎片,早晚都会申请内存失败;并且在比较复杂的代码或者继承的屎山中,非常容易出现内存泄漏导致mmo的问题。
C语言与CPP编程
2023/09/06
5.8K0
手把手带你用C/C++实现一个内存池(图文结合)
内存池的实现
经过了线程池,连接池的作用,内存池也就好理解了。内存池是专门使用数据结构将内存分配的任务交给内存池,不用每次分配内存的时候都自己使用 malloc 之类的。
ge3m0r
2024/05/26
1880
Nginx(11):存储数组的链表
它,是deque吗?deque,刚开始接触的时候有那么一丝欣喜,但是再进一步了解之后,嗯,大家不喜欢用是有原因的。
看、未来
2021/10/09
5240
Nginx(11):存储数组的链表
nginx平台初探(100%)
众所周知,nginx性能高,而nginx的高性能与其架构是分不开的。那么nginx究竟是怎么样的呢?这一节我们先来初识一下nginx框架吧。
用户5640963
2019/07/26
1.2K0
nginx平台初探(100%)
【Nginx】磁盘文件写入飞地发
文章继续。什么时候Nginx当用户请求一个文件,这将无法读取该文件的内容加载到内存,然后从内存发送,但电话sendfile况下,从内核直接发送出去。这样做显然效率要更高。Nginx也为我们封装好了一系列的接口。以下就来说明怎样发送一个磁盘文件给client。
全栈程序员站长
2022/07/05
1K0
【Nginx】磁盘文件写入飞地发
【Nginx 源码学习】推荐:Hash表
1、静态只读。当初始化生成hash表结构后,是不能动态修改这个hash表结构的内容。 2、将内存利用最大化。Nginx的hash表,将内存利用率发挥到了极致。 3、查询速度快。Nginx的hash表做了内存对齐等优化。 4、主要解析配置数据。
看、未来
2022/01/10
7720
【Nginx 源码学习】推荐:Hash表
nginx源码阅读(2)master和worker进程创建流程
ngx_uint_t log_use_stderr; /* unsigned log_use_stderr:1; */
golangLeetcode
2022/08/02
4390
nginx ngx_http_dyups_module模块源码分析
nginx 动态修改upstream不reload nginx模块,ngx_http_dyups_module分析。
stan1ey
2021/06/07
1.5K0
nginx坑记录
问题1: 配置解析过程使用ngx_cycle->pool申请内存保存配置,结果造成野指针。
用户1215536
2019/09/25
6660
Nginx(四):http服务器静态文件查找的实现
上一篇nginx的文章中,我们理解了整个http正向代理的运行流程原理,主要就是事件机制接入,header解析,body解析,然后遍历各种checker,直到处理成功为止。
烂猪皮
2021/01/28
1.9K2
Nginx(四):http服务器静态文件查找的实现
相关推荐
Nginx源码剖析之内存池,与内存管理
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验