slab分配object
在numa架构下,slab分配object:
3192static __always_inline void *
3193__do_cache_alloc(struct kmem_cache *cache, gfp_t flags)
{
void *objp; ...
objp = ____cache_alloc(cache, flags); /*
3205 * We may just have run out of memory on the local node.
3206 * ____cache_alloc_node() knows how to locate memory on other nodes
3207 */
if (!objp)
objp = ____cache_alloc_node(cache, flags, numa_mem_id()); out:
return objp;
}
首先,调用____cache_alloc来分配,该函数实现如下:
2920static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags)
{
void *objp;
struct array_cache *ac;
bool force_refill = false; check_irq_off(); ac = cpu_cache_get(cachep);
if (likely(ac->avail)) {
ac->touched = ;
objp = ac_get_obj(cachep, ac, flags, false); /*
2934 * Allow for the possibility all avail objects are not allowed
2935 * by the current flags
2936 */
if (objp) {
STATS_INC_ALLOCHIT(cachep);
goto out;
}
force_refill = true;
} STATS_INC_ALLOCMISS(cachep);
objp = cache_alloc_refill(cachep, flags, force_refill);
/*
2947 * the 'ac' may be updated by cache_alloc_refill(),
2948 * and kmemleak_erase() requires its correct value.
2949 */
ac = cpu_cache_get(cachep);
out:
/*
2954 * To avoid a false negative, if an object that is in one of the
2955 * per-CPU caches is leaked, we need to make sure kmemleak doesn't
2956 * treat the array pointers as a reference to the object.
2957 */
if (objp)
kmemleak_erase(&ac->entry[ac->avail]);
return objp;
}
1. 先从array cache里面去找,如果找到,返回,如果没找到,走到2.
2.调用cache_alloc_refill来从node的shared里去找object,或者slab的partial/free list里面获取object然后填充到cpu的array cache.
cache_alloc_refill实现如下:
2751static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags,
bool force_refill)
{
int batchcount;
struct kmem_cache_node *n;
struct array_cache *ac;
int node; check_irq_off();
node = numa_mem_id();
if (unlikely(force_refill))
goto force_grow;
2763retry:
ac = cpu_cache_get(cachep);
batchcount = ac->batchcount;
if (!ac->touched && batchcount > BATCHREFILL_LIMIT) {
/*
2768 * If there was little recent activity on this cache, then
2769 * perform only a partial refill. Otherwise we could generate
2770 * refill bouncing.
2771 */
batchcount = BATCHREFILL_LIMIT;
}
n = get_node(cachep, node); BUG_ON(ac->avail > || !n);
spin_lock(&n->list_lock); /* See if we can refill from the shared array */
if (n->shared && transfer_objects(ac, n->shared, batchcount)) {
n->shared->touched = ;
goto alloc_done;
} while (batchcount > ) {
struct list_head *entry;
struct page *page;
/* Get slab alloc is to come from. */
entry = n->slabs_partial.next;
if (entry == &n->slabs_partial) {
n->free_touched = ;
entry = n->slabs_free.next;
if (entry == &n->slabs_free)
goto must_grow;
} page = list_entry(entry, struct page, lru);
check_spinlock_acquired(cachep); /*
2801 * The slab was either on partial or free list so
2802 * there must be at least one object available for
2803 * allocation.
2804 */
BUG_ON(page->active >= cachep->num); while (page->active < cachep->num && batchcount--) {
STATS_INC_ALLOCED(cachep);
STATS_INC_ACTIVE(cachep);
STATS_SET_HIGH(cachep); ac_put_obj(cachep, ac, slab_get_obj(cachep, page,
node));
} /* move slabp to correct slabp list: */
list_del(&page->lru);
if (page->active == cachep->num)
list_add(&page->lru, &n->slabs_full);
else
list_add(&page->lru, &n->slabs_partial);
} 2824must_grow:
n->free_objects -= ac->avail;
2826alloc_done:
spin_unlock(&n->list_lock); if (unlikely(!ac->avail)) {
int x;
2831force_grow:
x = cache_grow(cachep, flags | GFP_THISNODE, node, NULL); /* cache_grow can reenable interrupts, then ac could change. */
ac = cpu_cache_get(cachep);
node = numa_mem_id(); /* no objects in sight? abort */
if (!x && (ac->avail == || force_refill))
return NULL; if (!ac->avail) /* objects refilled by interrupt? */
goto retry;
}
ac->touched = ; return ac_get_obj(cachep, ac, flags, force_refill);
}
3. 若从n->shared里面可以transfer nr(nr>0)个object,返回,分配成功。
4. 若n->shared也没有可用的object,则从slab的partial/free list里获取object,填充ac.
page->active是该slab里面已经使用的object的数量。
ac->available是ac里面可用的object的index.递减使用。
注意2825 n->free_objects -= ac->avail; 说明当ac被填充后,该ac里面的object就认为被分配出去了。
如果3和4均未成功transfer object到ac,只能重新申请slab。如cache_grow的实现:
2588static int cache_grow(struct kmem_cache *cachep,
gfp_t flags, int nodeid, struct page *page)
{
void *freelist;
size_t offset;
gfp_t local_flags;
struct kmem_cache_node *n; /*
2597 * Be lazy and only check for valid flags here, keeping it out of the
2598 * critical path in kmem_cache_alloc().
2599 */
BUG_ON(flags & GFP_SLAB_BUG_MASK);
local_flags = flags & (GFP_CONSTRAINT_MASK|GFP_RECLAIM_MASK); /* Take the node list lock to change the colour_next on this node */
check_irq_off();
n = get_node(cachep, nodeid);
spin_lock(&n->list_lock); /* Get colour for the slab, and cal the next value. */
offset = n->colour_next;
n->colour_next++;
if (n->colour_next >= cachep->colour)
n->colour_next = ;
spin_unlock(&n->list_lock); offset *= cachep->colour_off; if (local_flags & __GFP_WAIT)
local_irq_enable(); /*
2621 * The test for missing atomic flag is performed here, rather than
2622 * the more obvious place, simply to reduce the critical path length
2623 * in kmem_cache_alloc(). If a caller is seriously mis-behaving they
2624 * will eventually be caught here (where it matters).
2625 */
kmem_flagcheck(cachep, flags); /*
2629 * Get mem for the objs. Attempt to allocate a physical page from
2630 * 'nodeid'.
2631 */
if (!page)
page = kmem_getpages(cachep, local_flags, nodeid);
if (!page)
goto failed; /* Get slab management. */
freelist = alloc_slabmgmt(cachep, page, offset,
local_flags & ~GFP_CONSTRAINT_MASK, nodeid);
if (!freelist)
goto opps1; slab_map_pages(cachep, page, freelist); cache_init_objs(cachep, page); if (local_flags & __GFP_WAIT)
local_irq_disable();
check_irq_off();
spin_lock(&n->list_lock); /* Make slab active. */
list_add_tail(&page->lru, &(n->slabs_free));
STATS_INC_GROWN(cachep);
n->free_objects += cachep->num;
spin_unlock(&n->list_lock);
return ;
2658opps1:
kmem_freepages(cachep, page);
2660failed:
if (local_flags & __GFP_WAIT)
local_irq_disable();
return ;
}
申请完pages之后,申请slabmgmt.如下:
2445static void *alloc_slabmgmt(struct kmem_cache *cachep,
struct page *page, int colour_off,
gfp_t local_flags, int nodeid)
{
void *freelist;
void *addr = page_address(page); if (OFF_SLAB(cachep)) {
/* Slab management obj is off-slab. */
freelist = kmem_cache_alloc_node(cachep->freelist_cache,
local_flags, nodeid);
if (!freelist)
return NULL;
} else {
freelist = addr + colour_off;
colour_off += cachep->freelist_size;
}
page->active = ;
page->s_mem = addr + colour_off;
return freelist;
}
slabmgmt可以放在slab内部,也可以放在slab外部。放在slab外部的条件如下:
/*
2195 * Determine if the slab management is 'on' or 'off' slab.
2196 * (bootstrapping cannot cope with offslab caches so don't do
2197 * it too early on. Always use on-slab management when
2198 * SLAB_NOLEAKTRACE to avoid recursive calls into kmemleak)
2199 */
if ((size >= (PAGE_SIZE >> )) && !slab_early_init &&
!(flags & SLAB_NOLEAKTRACE))
/*
2203 * Size is large, assume best to place the slab management obj
2204 * off-slab (should allow better packing of objs).
2205 */
flags |= CFLGS_OFF_SLAB;
|
colour_off |
freelist_size |
obj… |
如果在管理节点在slab内部,结构图如上。如果开启了CONFIG_DEBUG_SLAB_LEAK宏,freelist_size后面还会有每个object的状态。
然后初始化page和object。
slab分配object的更多相关文章
- slub分配object
kmem_cache如下: 62struct kmem_cache { struct kmem_cache_cpu __percpu *cpu_slab; /* Used for retriving ...
- NGINX原理分析 之 SLAB分配机制
1 引言 众所周知,操作系统使用伙伴系统管理内存,不仅会造成大量的内存碎片,同时处理效率也较低下.SLAB是一种内存管理机制,其拥有较高的处理效率,同时也 有效的避免内存碎片的产生,其核心思想是预分配 ...
- [置顶] NGINX原理分析之SLAB分配机制
一.基础概述 如果使用伙伴系统分配和释放算法,不仅会造成大量的内存碎片,同时处理效率也比较低.SLAB是一种内存管理机制,其核心思想是预分配.SLAB是将空间按照SIZE对内存进行分类管理的,当申请一 ...
- NGINX原理 之 SLAB分配机制(转)
1 引言 众所周知,操作系统使用伙伴系统管理内存,不仅会造成大量的内存碎片,同时处理效率也较低下.SLAB是一种内存管理机制,其拥有较高的处理效率,同时也有效的避免内存碎片的产生,其核心思想是预分配. ...
- [转载]NGINX原理分析 之 SLAB分配机制
作者:邹祁峰 邮箱:Qifeng.zou.job@hotmail.com 博客:http://blog.csdn.net/qifengzou 日期:2013.09.15 23:19 转载请注明来自&q ...
- Linux内存分配----SLAB
动态内存管理 内存管理的目标是提供一种方法,为实现各种目的而在各个用户之间实现内存共享.内存管理方法应该实现以下两个功能: 最小化管理内存所需的时间 最大化用于一般应用的可用内存(最小化管理开销) 内 ...
- Linux内存分配机制之伙伴系统和SLAB
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6539590.html 内核内存管理的一项重要工作就是如何在频繁申请释放内存的情况下,避免碎片的产生.这就要求 ...
- Linux内存管理之slab分配器
slab分配器是什么? 参考:http://blog.csdn.net/vanbreaker/article/details/7664296 slab分配器是Linux内存管理中非常重要和复杂的一部分 ...
- slab机制
1.内部碎片和外部碎片 外部碎片 什么是外部碎片呢?我们通过一个图来解释: 假设这是一段连续的页框,阴影部分表示已经被使用的页框,现在需要申请一个连续的5个页框.这个时候,在这段内存上不能找到连续的5 ...
随机推荐
- malloc/calloc/realloc/alloca内存分配函数
calloc(), malloc(), realloc(), free(),alloca() 内存区域可以分为栈.堆.静态存储区和常量存储区,局部变量,函数形参,临时变量都是在栈上获得内存的,它们获取 ...
- thinkphp5.0 column多字段问题
一个字段:返回一维数组,数字索引为键名: 二个字段:返回一维数组,第一个字段为键名,第二个字段为元素值: 三个或更多字段:返回二维数组,第一个字段为键名,全部字段值为数据元素: 指定键名:方法的第二个 ...
- Oracle笔记(七) 数据更新、事务处理、数据伪列
一.数据的更新操作 DML操作语法之中,除了查询之外还有数据的库的更新操作,数据的更新操作主要指的是:增加.修改.删除数据,但是考虑到emp表以后还要继续使用,所以下面先将emp表复制一份,输入如下指 ...
- Oracle【多表查询操作(SQL92&SQL99)】
多表联合查询:需要获取的数据分布在多张表中 SQL92: --笛卡尔积:将多个表的数据进行一一对应,所得的结果为多表的笛卡尔积 select * from emp; select * from dep ...
- 十,StatefulSet简介及简单使用
目录 StatefulSet简介 为什么要用statefulset控制器 简单测试 使用 StatefulSet 创建基础的PV StatefulSet 清单 statefulset管理pod的启停顺 ...
- 修改虚拟机CentOS系统ip地址和主机名
按照教程安装了虚拟机但是未配置静态IP,所以导致IP地址经常变化,CRT,mysql等连接时经常出现问题. 所以修改虚拟机内CentOS系统的IP为静态IP. 一.查看当前网关 虚拟机-->[编 ...
- PAT Basic 1021 个位数统计 (15 分)
给定一个 k 位整数 1 (0, ,, dk−1>0),请编写程序统计每种不同的个位数字出现的次数.例如:给定 0,则有 2 个 0,3 个 1,和 1 个 3. 输入格式: 每个输入包含 ...
- JS 获取和返填单选按钮Value值
1.获取Radio值 $('input[name="sex"]:checked ').val(); 2.返填Radio值 $('input[name="sex" ...
- Python学习笔记:序列构成的数组
列表推导是一种构建列表(list)的快捷方式 #列表推导 symbols = '!@#$%' codes = [ord(symbol) for symbol in symbols] #ord()Pyt ...
- --print-defaults打印mysqld启动加载配置
Mysql启动配置文件加载路径 Mysql可以读取到的配置文件 /etc/my.cnf /etc/mysql/my.cnf /usr/local ...