Nginx --- 内存分配
作者:hahaya
日期:
Nginx内存分配简介
Nginx内存分配的源码主要位于${NGX_ROOT}/src/os/unix/ngx_alloc{.h|.c}文件中,Nginx提供ngx_alloc、ngx_calloc和ngx_memalign三个内存分配相关的函数,其中ngx_alloc和ngx_calloc是对系统malloc函数的封装,ngx_memalign在Linux系统下是对系统posix_memalign函数的封装,而在Solaris系统下是对系统memalign函数的封装,在其他系统下则是对ngx_alloc的define。既然Nginx提供了内存分配的函数,同样相应的也提供了内存释放的函数ngx_free,ngx_free仅仅是对系统函数free的define,因为malloc、posix_memalign、memalign分配的内存都是通过free函数释放的。
源码分析
ngx_alloc.h
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/
#ifndef _NGX_ALLOC_H_INCLUDED_
#define _NGX_ALLOC_H_INCLUDED_
#include <ngx_config.h>
#include <ngx_core.h>
void *ngx_alloc(size_t size, ngx_log_t *log); /* 分配内存 不进行初始化 */
void *ngx_calloc(size_t size, ngx_log_t *log); /* 分配内存 并自动初始化内存空间为0 */
#define ngx_free free /* 释放内存 */
/*
* Linux has memalign() or posix_memalign()
* Solaris has memalign()
* FreeBSD 7.0 has posix_memalign(), besides, early version's malloc()
* aligns allocations bigger than page size at the page boundary
*/
/*
* 封装 posix_memalign,如果是 Solaris 则封装 memalign
* 根据当前电脑配置自动生成NGX_HAVE_MEMALIGN NGX_HAVE_POSIX_MEMALIGN宏
* 包含顺序为${NGX_ROOT}/src/core/ngx_config.h -> ${NGX_ROOT}/objs/ngx_auto_headers.h
* ngx_auto_headers.h中判断操作系统的相关类型等 根据不同的系统包含不同的系统头文件
* 测试机器为Linux 故接着通过ngx_config.h包含 ${NGX_ROOT}/src/os/unixngx_linux_config.h
* 接着包含${NGX_ROOT}/objs/ngx_auto_config.h
*
* note:ngx_auto_headers.h和ngx_auto_config.h文件是在配置Nginx过程中生成的(./configure过程)
*/
#if (NGX_HAVE_POSIX_MEMALIGN || NGX_HAVE_MEMALIGN)
/*
* 内存分配对齐
*/
void *ngx_memalign(size_t alignment, size_t size, ngx_log_t *log);
#else
/*
* 其他系统下,如果不存在内存分配对齐函数memalign()或posix_memalign 则直接使用ngx_alloc代替
*/
#define ngx_memalign(alignment, size, log) ngx_alloc(size, log)
#endif
/*
* 声明三个外部使用的变量
* 全局变量ngx_alloc.c中定义 ${NGX_ROOT}/src/os/unix/ngx_posix_init.c中初始化
* 为了方便后面内存池等需要内存分配的地方使用而不用每次extern
* 即避免每个需要使用的文件中extern这三个变量 故放在ngx_malloc.h中
*/
extern ngx_uint_t ngx_pagesize; /* 页大小 */
extern ngx_uint_t ngx_pagesize_shift; /* 页大小对应的移位数 */
extern ngx_uint_t ngx_cacheline_size; /* 缓存大小 */
#endif /* _NGX_ALLOC_H_INCLUDED_ */
ngx_alloc.c
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/
#include <ngx_config.h>
#include <ngx_core.h>
/* 三个变量的定义 */
ngx_uint_t ngx_pagesize;
ngx_uint_t ngx_pagesize_shift;
ngx_uint_t ngx_cacheline_size;
/*
* 分配内存 主要是对系统函数malloc的封装
* 增加分配内存失败的判断机制 内存分配失败时写入日志文件
*/
void *
ngx_alloc(size_t size, ngx_log_t *log)
{
void *p;
/* 调用malloc分配内存 */
p = malloc(size);
/* 分配内存失败 将错误信息写入日志文件 */
if (p == NULL) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
"malloc(%uz) failed", size);
}
/* DEBUG模式下的处理 */
ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, log, 0, "malloc: %p:%uz", p, size);
return p;
}
/*
* 分配内存 并将分配的内存初始化为0
* 封装ngx_alloc之后调用ngx_memzero初始化内存为0
*/
void *
ngx_calloc(size_t size, ngx_log_t *log)
{
void *p;
//分配内存
p = ngx_alloc(size, log);
//内存初始化
if (p) {
ngx_memzero(p, size);
}
return p;
}
#if (NGX_HAVE_POSIX_MEMALIGN)
/*
* Linux系统下调用posix_memalign进行内存分配和内存对齐
*
*/
void *
ngx_memalign(size_t alignment, size_t size, ngx_log_t *log)
{
void *p;
int err;
/*
* 背景:
* 1)POSIX 1003.1d
* 2)POSIX 标明了通过malloc( ), calloc( ), 和 realloc( ) 返回的地址对于任何的C类型来说都是对齐的
* 功能:由posix_memalign分配的内存空间,需要由free释放。
* 参数:
* p 分配好的内存空间的首地址
* alignment 对齐边界,Linux中,32位系统是8字节,64位系统是16字节
* size 指定分配size字节大小的内存
* 要求:
* 1)要求alignment是2的幂,并且是p指针大小的倍数
* 2)要求size是alignment的倍数
* 返回:
* 0 成功
* EINVAL 参数不满足要求
* ENOMEM 内存分配失败
* 注意:
* 1)该函数不影响errno,只能通过返回值判
* 2)在32位系统下malloc、calloc分配的内存是8字节为边界对齐的 即返回的内存地址起始值是8的倍数
* 3)在64位系统下malloc、calloc分配的内存时16字节为边界对齐的 即返回的内存地址起始值是16的倍数
* 4)有时候,对齐更大的边界,例如页面等,程序员需要动态的对齐,于是出现了posix_memalign函数
* 5)posix_memalign函数分配内存返回的内存地址起始值是alignment的倍数
*/
err = posix_memalign(&p, alignment, size);
/* 内存分配失败 */
if (err) {
ngx_log_error(NGX_LOG_EMERG, log, err,
"posix_memalign(%uz, %uz) failed", alignment, size);:w
p = NULL;
}
ngx_log_debug3(NGX_LOG_DEBUG_ALLOC, log, 0,
"posix_memalign: %p:%uz @%uz", p, size, alignment);
return p;
}
#elif (NGX_HAVE_MEMALIGN)
/*
* Solaris系统下调用memalign进行内存分配和内存对齐
*
*/
void *
ngx_memalign(size_t alignment, size_t size, ngx_log_t *log)
{
void *p;
p = memalign(alignment, size);
/* 内存分配失败 */
if (p == NULL) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
"memalign(%uz, %uz) failed", alignment, size);
}
ngx_log_debug3(NGX_LOG_DEBUG_ALLOC, log, 0,
"memalign: %p:%uz @%uz", p, size, alignment);
return p;
}
#endif
测试
为了方便测试和学习Nginx的内存分配,以免引入过多的文件,没有使用Nginx中的文件包含机制,去掉了出现分配错误后写入日志文件的操作,并且只关注Linux系统,测试代码如下:
ngx_alloc.h
#ifndef _NGX_ALLOC_H_INCLUDE_
#define _NGX_ALLOC_H_INCLUDE_
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
/* 分配内存 */
void *ngx_alloc(size_t size);
void *ngx_calloc(size_t size);
void *ngx_memalign(size_t alignment, size_t size);
/* 释放内存 */
#define ngx_free free
#endif
ngx_alloc.c
#include "ngx_alloc.h"
void *ngx_alloc(size_t size)
{
void *p;
p = malloc(size);
if (NULL == p) {
printf("malloc %d memory failed.\n", (int)size);
} else {
printf("malloc %d memory success.\n", (int)size);
}
return p;
}
void *ngx_calloc(size_t size)
{
void *p;
p = ngx_alloc(size);
if (p) {
memset(p, 0, size);
}
return p;
}
void *ngx_memalign(size_t alignment, size_t size)
{
void *p;
int err;
err = posix_memalign(&p, alignment, size);
if (err) {
printf("posix_memalign %d memory failed.\n", (int)size);
p = NULL;
} else {
printf("posix_memalign %d memory success.\n", (int)size);
}
return p;
}
ngx_alloc_test.c
#include "ngx_alloc.h"
int main()
{
//ngx_alloc
void *p_alloc = ngx_alloc(100);
printf("p_alloc address:%X\n", p_alloc);
ngx_free(p_alloc);
//ngx_calloc
char *p_calloc = (char*)ngx_calloc(100);
printf("p_calloc address:%X\n", p_calloc);
ngx_free(p_calloc);
//ngx_memalign
void *p_memalign = ngx_memalign(32, 1024);
printf("p_memalign address:%X\n", p_memalign);
ngx_free(p_memalign);
return 0;
}
makefile
cc = gcc
target = ngx_alloc_test
objs = ngx_alloc.o ngx_alloc_test.o
$(target):$(objs)
$(cc) $(objs) -o $(target)
ngx_alloc.o:ngx_alloc.h ngx_alloc.c
$(cc) -c -w ngx_alloc.c
ngx_alloc_test.o:ngx_alloc_test.c
$(cc) -c -w ngx_alloc_test.c
clean:
rm $(target) $(objs)
作者:hahaya
出处:http://hahaya.github.com/memory-alloc-in-nginx
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
出处:http://hahaya.github.com/memory-alloc-in-nginx
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。