与小块内存不同,大块内存通常指的是那些大小较大、分配和释放频率相对较低的内存块。
ngx_palloc_large函数
当Nginx需要分配一块大块内存时,它通常会直接调用操作系统的内存分配函数(如malloc、calloc或posix_memalign等)。这些函数会根据请求的大小在操作系统的内存空间中寻找一块合适的连续内存区域,并将其分配给Nginx使用。由于大块内存的大小通常较大,因此操作系统能够更容易地找到满足需求的连续内存空间。
在分配大块内存时,Nginx通常不会过多进行额外的内存池检查或预分配操作。这是因为大块内存的分配和释放相对较为罕见,且频繁地进行内存池检查会增加不必要的开销。
源码及注释:
static void *
ngx_palloc_large(ngx_pool_t *pool, size_t size)
{
void *p;
ngx_uint_t n;
ngx_pool_large_t *large; // 结构体中有下块地址next和本块内存地址alloc
p = ngx_alloc(size, pool->log); // malloc 开辟大块内存
if (p == NULL) {
return NULL;
}
n = 0;
for (large = pool->large; large; large = large->next) {
// 复用大块内存头信息体链表中,现有的空头信息体
// alloc为空是先前通过pfree函数释放的
// 此举是为了不去创建新的大内存头信息体,复用之前归还的大内存头信息体
if (large->alloc == NULL) {
large->alloc = p;
return p;
}
if (n++ > 3) { // 防止找的次数太多浪费时间
break;
}
}
// 在小块内存池中,存放大块内存的头信息体
large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);
if (large == NULL) { // 没有开辟成功
ngx_free(p); // 把新创建的大块内存空间free掉
return NULL;
}
large->alloc = p; // 头结点记录大块内存的地址信息
large->next = pool->large; // 大块内存头信息体 头插法进链表
pool->large = large;
return p;
}
大块内存结构示意图:
ngx_alloc内存分配函数
ngx_alloc也是平台相关的alloc函数,不必纠结:
ngx_pfree大块内存释放函数
ngx_int_t
ngx_pfree(ngx_pool_t *pool, void *p) // 释放大块内存,不释放小块内存
{
ngx_pool_large_t *l;
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); // 可理解为free函数,释放内存
l->alloc = NULL; // 头信息体中地址域置空
return NGX_OK; // #define NGX_OK 0
}
}
return NGX_DECLINED; // #define NGX_DECLINED -5
}
ngx_free——平台相关的free函数
总结
Nginx对于大块内存是调用系统的内存分配函数,然后将内存地址通过信息结构体进行管理。
当Nginx不再需要一块大块内存时,它会调用操作系统的内存释放函数(如free)来将内存归还给操作系统。与分配过程类似,Nginx在释放大块内存时也不会进行额外的内存池管理操作。相反,它会依赖于操作系统的内存管理机制来自动处理内存碎片和回收工作。
相对于小块内存的只有分配逻辑没有释放逻辑,大块内存两者都有。