在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的更多相关文章

  1. slub分配object

    kmem_cache如下: 62struct kmem_cache { struct kmem_cache_cpu __percpu *cpu_slab; /* Used for retriving ...

  2. NGINX原理分析 之 SLAB分配机制

    1 引言 众所周知,操作系统使用伙伴系统管理内存,不仅会造成大量的内存碎片,同时处理效率也较低下.SLAB是一种内存管理机制,其拥有较高的处理效率,同时也 有效的避免内存碎片的产生,其核心思想是预分配 ...

  3. [置顶] NGINX原理分析之SLAB分配机制

    一.基础概述 如果使用伙伴系统分配和释放算法,不仅会造成大量的内存碎片,同时处理效率也比较低.SLAB是一种内存管理机制,其核心思想是预分配.SLAB是将空间按照SIZE对内存进行分类管理的,当申请一 ...

  4. NGINX原理 之 SLAB分配机制(转)

    1 引言 众所周知,操作系统使用伙伴系统管理内存,不仅会造成大量的内存碎片,同时处理效率也较低下.SLAB是一种内存管理机制,其拥有较高的处理效率,同时也有效的避免内存碎片的产生,其核心思想是预分配. ...

  5. [转载]NGINX原理分析 之 SLAB分配机制

    作者:邹祁峰 邮箱:Qifeng.zou.job@hotmail.com 博客:http://blog.csdn.net/qifengzou 日期:2013.09.15 23:19 转载请注明来自&q ...

  6. Linux内存分配----SLAB

    动态内存管理 内存管理的目标是提供一种方法,为实现各种目的而在各个用户之间实现内存共享.内存管理方法应该实现以下两个功能: 最小化管理内存所需的时间 最大化用于一般应用的可用内存(最小化管理开销) 内 ...

  7. Linux内存分配机制之伙伴系统和SLAB

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6539590.html  内核内存管理的一项重要工作就是如何在频繁申请释放内存的情况下,避免碎片的产生.这就要求 ...

  8. Linux内存管理之slab分配器

    slab分配器是什么? 参考:http://blog.csdn.net/vanbreaker/article/details/7664296 slab分配器是Linux内存管理中非常重要和复杂的一部分 ...

  9. slab机制

    1.内部碎片和外部碎片 外部碎片 什么是外部碎片呢?我们通过一个图来解释: 假设这是一段连续的页框,阴影部分表示已经被使用的页框,现在需要申请一个连续的5个页框.这个时候,在这段内存上不能找到连续的5 ...

随机推荐

  1. Spring的核心jar包

    Spring的主要jar包 四个核心jar包:beans.context.core.expression Spring AOP:Spring的面向切面编程,提供AOP(面向切面编程)的实现Spring ...

  2. mint-ui下拉加载(项目实例)

    <template> <div class="share"> <div class="header"> <div cl ...

  3. navicat连接阿里云mysql

    1.服务器控制台在安全组配置3306端口 2.进入 /etc/ssh/sshd_config 在最下面 加入下面代码 KexAlgorithms diffie-hellman-group1-sha1, ...

  4. 使用Parallel计算目录中的文件字节长度

    /// <summary> /// 根据通配符和搜索条件计算给定目录中的文件字节长度 /// </summary> /// <param name="path& ...

  5. 【audition CC】将3分钟的歌曲无缝延长到15分钟

  6. go学习开篇

            我是做java开发的,从接触java开始算,已经8年了,为什么会想到学go语言呢?前端时间我一直在学习jvm,java的一些更底层的东西,梳理回顾时,感觉可以通过学习其他开发语言,来提 ...

  7. Java-20180412

    今天开始重新复习Java,完成了leetcode的第一题. 1.算法: 给定一个数组和目标值,找出相加等于目标值的数组元素的下标. 数组[2,7,11,15]; target:9; 返回:[0,1]; ...

  8. 由函数$y=\sin x$的图像伸缩变换为函数$y=\sin(\omega x)$的图像(交互式)

    可以拖动滑动条\(\omega\)显示动态效果

  9. JVM的四种GC算法

    程序在运行过程中,会产生大量的内存垃圾(一些没有引用指向的内存对象都属于内存垃圾,因为这些对象已经无法访问,程序用不了它们了,对程序而言它们已经死亡),为了确保程序运行时的性能,java虚拟机在程序运 ...

  10. MySQL数据优化总结-查询备忘录

    一.优化分类 二.测试数据样例 参考mysql官方的sakina数据库. 三.使用mysql慢查询日志对有效率问题的sql进行监控 第一个,开启慢查询日志.第二个,慢查询日志存储位置.第三个,没有使用 ...