-
malloc开始搜索空闲内存块,如果能找到一块大小合适的就分配出去
-
如果malloc找不到一块合适的空闲内存,那么调用brk等系统调用扩大堆区从而获得更多的空闲内存
-
malloc调用brk后开始转入内核态,此时操作系统中的虚拟地址系统开始工作,扩大进程的堆区,操作系统并没有为此分配真正的物理内存
-
brk执行结束后返回到malloc,从内核态切换到用户态,malloc找到一块合适的空闲内存后返回
-
进程拿到内存,继续干活。
-
当有代码读写新申请的内存时系统内部出现缺页中断,此时再次由用户态切换到内核态,操作系统此时真正的分配物理内存,之后再次由内核态切换回用户态,程序继续。
如果对堆和栈有所了解的朋友应该会知道,堆是像上伸展的,栈是向下延伸的,那什么向上向下啊?有点迷哈。看个图:
一切尽在不言中咯。
说实话啊,这俩我都没有用过呢,也是第一次听,先把概念放这儿,之后有时间了研究研究。
Nginx 使用内存池对内存进行管理,把内存分配归结为大内存分配和小内存分配,申请的内存大小比同页的内存池最大值 max 还 大,则是大内存分配,否则为小内存分配。
-
大块内存的分配请求不会直接在内存池上分配内存来满足请求,而是直接向系统申请一块内存(就像 直接使用 malloc 分配内存一样),然后将这块内存挂到内存池头部的 large 字段下。
-
小块内存分配,则是从已有的内存池数据区中分配出一部分内存。
Nginx 内存分配总流图如下:其中 size 是用户请求分配内存的大小,pool是现有内存池。
基础数据结构
数据块:
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; // 指向当前内存池
ngx_chain_t *chain; // 该指针挂接一个ngx_chain_t结构
ngx_pool_large_t *large; // 大块内存链表,即分配空间超过max的内存
ngx_pool_cleanup_t *cleanup; // 释放内存池的callback
ngx_log_t *log; // 主要用于记录日志信息
};
大块内存:
struct ngx_pool_large_s {
ngx_pool_large_t *next; // 指向下一个large内存
void *alloc; // 指向分配的large内存
};
回收站:
struct