Nginx slab的实现 --- 第二篇“基于页的内存分配”
来源:互联网 发布:酷派手机自动开启数据 编辑:程序博客网 时间:2024/06/10 11:22
摘要: 本篇在上一篇“基本布局”的基础上介绍“基于页的内存分配”机制,也为后续讲解“基于块的内存分配”机制做个铺垫。
说明:本系列的文章基于Nginx-1.5.0版本代码。
在上一篇中已经介绍了Nginx slab分配器的基本原理和内存空间布局,现在我们将在此基础上引入“基于页的内存分配”的相关内容。之所以这样安排是因为它的实现相对于“基于块的内存分配”要简单许多,同时它又是“基于块的内存分配”的基础,以它为突破口怎么看都是最好的选择:)
在”基于页的内存分配“流程中只需要用到”page页内存管理单元“,而不涉及”分级内存管理单元“,为了方便讨论,我们将初始化后的内存布局图简化如下:
一、内存的分配
Nginx slab本身没有对外提供专门的按页分配内存的接口,具体采用哪种分配方式是在内部根据传入的size值并结合一定的算法来进行决策的。以ngx_slab_alloc为例:
void *ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size){ void *p; ngx_shmtx_lock(&pool->mutex); p = ngx_slab_alloc_locked(pool, size); ngx_shmtx_unlock(&pool->mutex); return p;}void *ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size){ size_t s; uintptr_t p, n, m, mask, *bitmap; ngx_uint_t i, slot, shift, map; ngx_slab_page_t *page, *prev, *slots; /*若要求分配的内存大小超过1/2页,则采用“按页分配”的方式*/ /*注意,这里的判断在最新的版本里好像已经改为">"了,因为1/2页本身就是一个管理分级*/ if (size >= ngx_slab_max_size) { ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab alloc: %uz", size); /*将size向上取整到页大小的整数倍上*/ page = ngx_slab_alloc_pages(pool, (size >> ngx_pagesize_shift) + ((size % ngx_pagesize) ? 1 : 0)); if (page) { p = (page - pool->pages) << ngx_pagesize_shift; p += (uintptr_t) pool->start; } else { p = 0; } goto done; } ... ...done: ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab alloc: %p", p); return (void *) p;}/*“基于页的内存分配”函数实现,参数为要求分配的页数*/static ngx_slab_page_t *ngx_slab_alloc_pages(ngx_slab_pool_t *pool, ngx_uint_t pages){ ngx_slab_page_t *page, *p; /*“free”是空闲页管理单元链表头*/ for (page = pool->free.next; page != &pool->free; page = page->next) { /*当前连续空闲空间中的页数是否能够满足分配的需求*/ if (page->slab >= pages) { /*若当前连续空闲空间在完成本次分配的要求后还有剩余页,则除了将本次待分配的页从空闲链表移除外,还需要将剩余部分挂接到空闲链表中*/ if (page->slab > pages) { page[pages].slab = page->slab - pages; page[pages].next = page->next; page[pages].prev = page->prev; p = (ngx_slab_page_t *) page->prev; p->next = &page[pages]; page->next->prev = (uintptr_t) &page[pages]; } else { p = (ngx_slab_page_t *) page->prev; p->next = page->next; page->next->prev = page->prev; } /*修改第一个分配页的相关标记值*/ page->slab = pages | NGX_SLAB_PAGE_START; page->next = NULL; page->prev = NGX_SLAB_PAGE; if (--pages == 0) { return page; } /*如果分配的页数大于一页,还需要修改后续页的标记值*/ for (p = page + 1; pages; pages--) { p->slab = NGX_SLAB_PAGE_BUSY; p->next = NULL; p->prev = NGX_SLAB_PAGE; p++; } return page; } } ngx_slab_error(pool, NGX_LOG_CRIT, "ngx_slab_alloc() failed: no memory"); return NULL;}
下面这两幅图非常直观地说明了当初始化完成之后(假设此时共有N个空闲页),分别申请m(< N)页和N页内存时的情形。
下面再进一步来看一下当进行过若干次页分配后的内存空间布局,这里我们假设分配的顺序为:m0页、1页、m1页、1页:
有了上面的几幅图,再结合ngx_slab_alloc_pages()的源码,就很容易理解“基于页的内存分配”流程和实现机制了。
0 0
- Nginx slab的实现 --- 第二篇“基于页的内存分配”
- Nginx slab的实现 --- 第三篇“基于块的内存分配”
- Nginx slab的实现 --- 第五篇“基于页的内存释放”
- Nginx slab的实现 --- 第四篇“基于块的内存释放”
- Nginx的slab page内存缓存机制
- Linux内核内存管理之SLAB内存管理算法(三) --slab对象的分配与释放
- 内存slab分配器的设计与实现
- Nginx slab 分配机制
- 内存的slab算法
- Nginx Proxy Cache的slab page内存缓存机制
- 内存管理-SLAB(SLAB的基本数据结构)
- 内存管理-SLAB(SLAB的基本数据结构)
- slab内存分配
- Linux的内存管理主要分为两部分:物理地址到虚拟地址的映射,内核内存分配管理(主要基于slab)。
- Java内存管理第二篇 - 内存的分配
- Java内存管理第二篇 - 内存的分配
- Java内存管理第二篇 - 内存的分配
- Nginx slab的实现 --- 第一篇“基本布局”
- CMake学习笔记(二)——CMake语法
- QT在构造函数中退出程序
- Android中的socket编程,基础
- iOS移动端架构的那些事
- 判定Java源文件名称
- Nginx slab的实现 --- 第二篇“基于页的内存分配”
- 注解(Annotation)自定义注解(二)--运行时注解解析
- 【解题报告】UVALive 3938 线段树深入使用
- leafletjs实现动态标记点【部分代码】
- 2017暑假实习生java开发工程师面试(京东)
- OpenWRT中英文支持
- http://www.cnblogs.com/zyw-205520/archive/2013/02/17/2914190.html
- C#学习之--线程Thread
- HTML5之arcTo()函数