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 ...
随机推荐
- 在python中,用默认参数(list,set,dict...)时要小心
在我们平时写需求的时候,如果没有了解到以下知识点,可能会出现这样的问题,掉进坑里面,甚至很难找到问题的根源.下面我们来看看使用可变默认参数(Mutable default arguments)时会出现 ...
- python自学笔记之开源小工具:SanicDB介绍
SanicDB 是为 Python的异步 Web 框架 Sanic 方便操作MySQL而开发的工具,是对 aiomysql.Pool 的轻量级封装.Sanic 是异步IO的Web框架,同时用异步IO读 ...
- python函数:函数使用原则、定义与调用形式
一.函数初始 二.函数的使用原则 三.函数的定义与调用形式 四.函数的返回值 五.函数参数的使用 一.函数初始 # 须知一: # 硬盘空间无法修改,硬盘中的数据更新都是用新的内容覆盖旧的内容 # 内存 ...
- thymeleaf错误 org.xml.sax.SAXParseException: 在实体引用中, 实体名称必须紧跟在 ‘&’ 后面
在thymeleaf的js中使用&,<,>等符号时会产生这种问题,因为thymeleaf是采用xml解析的方式进行替换的,所以javascript中&这样的xml实体转义字 ...
- Maven编译
多模块 只有需要编译成jar的模块才设置build <build> <plugins> <plugin> <groupId>org.springfram ...
- .NET Core 3时代DevExpress Winforms v19.2增强Scheduler控件
DevExpress Winforms Controls 内置140多个UI控件和库,完美构建流畅.美观且易于使用的应用程序.无论是Office风格的界面,还是分析处理大批量的业务数据,DevExpr ...
- Web UI开发推荐!Kendo UI for jQuery自定义小部件——处理事件
Kendo UI for jQuery最新试用版下载 Kendo UI目前最新提供Kendo UI for jQuery.Kendo UI for Angular.Kendo UI Support f ...
- JS自带的map()方法
1. map()方法返回一个由原数组的每个元素调用一个指定方法后返回值组成的新数组. 2. 例子: 2.1 在字符串中使用map 在一个String上使用map方法获取字符串中每个字符所对应的ASCI ...
- 运维堡垒机(跳板机)系统 python
相信各位对堡垒机(跳板机)不陌生,为了保证服务器安全,前面加个堡垒机,所有ssh连接都通过堡垒机来完成,堡垒机也需要有 身份认证,授权,访问控制,审计等功能,笔者用Python基本实现了上述功能. A ...
- hive日期函数-广发实战(三)
近一月客户新增常规里程数与额度比即上个月 第一天(包含)到上个月最后一天(包含) 字段是batch_date==>格式是 yyyymmdd ),'MM'),'-',''); +--------- ...