Linux内核中内存cache的实现【转】
// 链表
struct list_head list;
// 未用空间的偏移
unsigned long colouroff;
// 具体的内存缓冲区地址
void *s_mem; /* including colour offset */
// 每个slab中的正在使用的对象数量
unsigned int inuse; /* num of objs active in slab */
// 空闲对象
kmem_bufctl_t free;
unsigned short nodeid;
};
// 这里只是一个类型定义
typedef struct kmem_cache kmem_cache_t;
// 在C文件中进行完整的定义
* struct array_cache
*
* Purpose:
* - LIFO ordering, to hand out cache-warm objects from _alloc
* - reduce the number of linked list operations
* - reduce spinlock operations
*
* The limit is stored in the per-cpu structure to reduce the data cache
* footprint.
*
*/
// 这是每个CPU对应的cache数据
struct array_cache {
unsigned int avail;
unsigned int limit;
unsigned int batchcount;
unsigned int touched;
spinlock_t lock;
void *entry[0]; /*
* Must have this definition in here for the proper
* alignment of array_cache. Also simplifies accessing
* the entries.
* [0] is for gcc 2.95. It should really be [].
*/
};
* The slab lists for all objects.
*/
// 这是cache管理的slab的链表
struct kmem_list3 {
// 该链表中slab中既有正在使用的对象,也有空闲对象
struct list_head slabs_partial; /* partial list first, better asm code */
// 该链表中slab的对象都在使用中
struct list_head slabs_full;
// 该链表中slab的对象都是空闲的
struct list_head slabs_free;
// 空闲的对象数
unsigned long free_objects;
// 空闲的限值,超过就该释放掉一些了
unsigned int free_limit;
unsigned int colour_next; /* Per-node cache coloring */
spinlock_t list_lock;
struct array_cache *shared; /* shared per node */
struct array_cache **alien; /* on other nodes */
unsigned long next_reap; /* updated without locking */
int free_touched; /* updated without locking */
};
/* 1) per-cpu data, touched during every alloc/free */
// 每个CPU对应的cache数组
struct array_cache *array[NR_CPUS];
/* 2) Cache tunables. Protected by cache_chain_mutex */
// 没有空闲对象时为处理器一次批量分配的对象数量
unsigned int batchcount;
// 在将缓冲池中一半空闲对象释放到全局缓冲池前缓冲池中允许的空闲对象的数量
unsigned int limit;
unsigned int shared;
//
unsigned int buffer_size;
/* 3) touched by every alloc & free from the backend */
// MAX_NUMNODES个cache节点链表,MAX_NUMNODES是编译内核时定义的
struct kmem_list3 *nodelists[MAX_NUMNODES];
// 每个slab中的对象数
unsigned int num; /* # of objs per slab */
/* order of pgs per slab (2^n) */
// 表明在内存页中的slab块的大小, 如果对象大小小于4K,该值为1
// 超过4K,该值为slab大小相对4K的倍数, 如对于32K, 该值为8
unsigned int gfporder;
gfp_t gfpflags;
unsigned int colour_off; /* colour offset */
struct kmem_cache *slabp_cache;
unsigned int slab_size;
unsigned int dflags; /* dynamic flags */
// cache构造函数
void (*ctor) (void *, struct kmem_cache *, unsigned long);
// cache析构函数
void (*dtor) (void *, struct kmem_cache *, unsigned long);
// cache的名称
const char *name;
// cache链表中的下一项
struct list_head next;
#if STATS
unsigned long num_active;
unsigned long num_allocations;
unsigned long high_mark;
unsigned long grown;
unsigned long reaped;
unsigned long errors;
unsigned long max_freeable;
unsigned long node_allocs;
unsigned long node_frees;
unsigned long node_overflow;
atomic_t allochit;
atomic_t allocmiss;
atomic_t freehit;
atomic_t freemiss;
#endif
#if DEBUG
/*
* If debugging is enabled, then the allocator can add additional
* fields and/or padding to every object. buffer_size contains the total
* object size including these internal fields, the following two
* variables contain the offset to the user object and its size.
*/
int obj_offset;
int obj_size;
#endif
};
static struct kmem_cache cache_cache = {
.batchcount = 1,
.limit = BOOT_CPUCACHE_ENTRIES,
.shared = 1,
.buffer_size = sizeof(struct kmem_cache),
.name = "kmem_cache",
#if DEBUG
.obj_size = sizeof(struct kmem_cache),
#endif
};
|
V
kmem_list3
|
+--------------------------------------+
| | |
V V V
slab_full slab_partial slab_free
| | |
V V V
slab slab slab
| | |
V V V
page page page
| | |
+-------------+ +--------------+ +-------------+
| | | | | |
V V V V V V
object ... object object ... object object ... object
sizeof(struct ip_conntrack), 0,
0, NULL, NULL);
这个函数重点就是根据所需要的内存块大小确定合适的、对齐的slab块大小
// name是该cache的名称
// size是cahce中对象的大小, 一般情况下其他参数都可为0或NULL
// align: 指定size要按align对齐
struct kmem_cache *
kmem_cache_create (const char *name, size_t size, size_t align,
unsigned long flags,
void (*ctor)(void*, struct kmem_cache *, unsigned long),
void (*dtor)(void*, struct kmem_cache *, unsigned long))
{
size_t left_over, slab_size, ralign;
struct kmem_cache *cachep = NULL, *pc;
* Sanity checks... these are all serious usage bugs.
*/
// cache名不能为空,不能在中断中分配,每个单元块不能太大,也不能太小
// 如果定义了析构函数不能没有构造函数
if (!name || in_interrupt() || (size < BYTES_PER_WORD) ||
(size > (1 << MAX_OBJ_ORDER) * PAGE_SIZE) || (dtor && !ctor)) {
printk(KERN_ERR "%s: Early error in slab %s\n", __FUNCTION__,
name);
BUG();
}
* Prevent CPUs from coming and going.
* lock_cpu_hotplug() nests outside cache_chain_mutex
*/
lock_cpu_hotplug();
mutex_lock(&cache_chain_mutex);
list_for_each_entry(pc, &cache_chain, next) {
mm_segment_t old_fs = get_fs();
char tmp;
int res;
* This happens when the module gets unloaded and doesn't
* destroy its slab cache and no-one else reuses the vmalloc
* area of the module. Print a warning.
*/
// 检查一下cache是否有效,可能会由于模块的释放却没清除掉
set_fs(KERNEL_DS);
res = __get_user(tmp, pc->name);
set_fs(old_fs);
if (res) {
printk("SLAB: cache with size %d has lost its name\n",
pc->buffer_size);
continue;
}
// 相同名称的cache已经有了,出错返回
if (!strcmp(pc->name, name)) {
printk("kmem_cache_create: duplicate cache %s\n", name);
dump_stack();
goto oops;
}
}
#if DEBUG
WARN_ON(strchr(name, ' ')); /* It confuses parsers */
if ((flags & SLAB_DEBUG_INITIAL) && !ctor) {
/* No constructor, but inital state check requested */
printk(KERN_ERR "%s: No con, but init state check "
"requested - %s\n", __FUNCTION__, name);
flags &= ~SLAB_DEBUG_INITIAL;
}
#if FORCED_DEBUG
/*
* Enable redzoning and last user accounting, except for caches with
* large objects, if the increased size would increase the object size
* above the next power of two: caches with object sizes just above a
* power of two have a significant amount of internal fragmentation.
*/
if (size < 4096 || fls(size - 1) == fls(size-1 + 3 * BYTES_PER_WORD))
flags |= SLAB_RED_ZONE | SLAB_STORE_USER;
if (!(flags & SLAB_DESTROY_BY_RCU))
flags |= SLAB_POISON;
#endif
if (flags & SLAB_DESTROY_BY_RCU)
BUG_ON(flags & SLAB_POISON);
#endif
if (flags & SLAB_DESTROY_BY_RCU)
BUG_ON(dtor);
* Always checks flags, a caller might be expecting debug support which
* isn't available.
*/
BUG_ON(flags & ~CREATE_MASK);
* Check that size is in terms of words. This is needed to avoid
* unaligned accesses for some archs when redzoning is used, and makes
* sure any on-slab bufctl's are also correctly aligned.
*/
// 将对象长度先按BYTES_PER_WORD扩展对齐, 32位机为4字节对齐
if (size & (BYTES_PER_WORD - 1)) {
size += (BYTES_PER_WORD - 1);
size &= ~(BYTES_PER_WORD - 1);
}
// 以下根据函数标志计算实际对齐值
/* 1) arch recommendation: can be overridden for debug */
if (flags & SLAB_HWCACHE_ALIGN) {
// 要根据硬件CACHE进行字节对齐,对齐都是2的指数倍
/*
* Default alignment: as specified by the arch code. Except if
* an object is really small, then squeeze multiple objects into
* one cacheline.
*/
ralign = cache_line_size();
while (size <= ralign / 2)
ralign /= 2;
} else {
ralign = BYTES_PER_WORD;
}
* Redzoning and user store require word alignment. Note this will be
* overridden by architecture or caller mandated alignment if either
* is greater than BYTES_PER_WORD.
*/
if (flags & SLAB_RED_ZONE || flags & SLAB_STORE_USER)
ralign = BYTES_PER_WORD;
if (ralign < ARCH_SLAB_MINALIGN) {
ralign = ARCH_SLAB_MINALIGN;
if (ralign > BYTES_PER_WORD)
flags &= ~(SLAB_RED_ZONE | SLAB_STORE_USER);
}
/* 3) caller mandated alignment: disables debug if necessary */
if (ralign < align) {
// 如果根据系统情况计算出的对齐值小于要求的对齐值,用参数里的对齐值
ralign = align;
if (ralign > BYTES_PER_WORD)
flags &= ~(SLAB_RED_ZONE | SLAB_STORE_USER);
}
/*
* 4) Store it.
*/
// 真正的对齐值
align = ralign;
// 分配cache本身的内存空间,并清零,SLAB_KERNEL标志表明该操作可能会休眠
cachep = kmem_cache_zalloc(&cache_cache, SLAB_KERNEL);
if (!cachep)
goto oops;
cachep->obj_size = size;
* Both debugging options require word-alignment which is calculated
* into align above.
*/
if (flags & SLAB_RED_ZONE) {
/* add space for red zone words */
cachep->obj_offset += BYTES_PER_WORD;
size += 2 * BYTES_PER_WORD;
}
if (flags & SLAB_STORE_USER) {
/* user store requires one word storage behind the end of
* the real object.
*/
size += BYTES_PER_WORD;
}
#if FORCED_DEBUG && defined(CONFIG_DEBUG_PAGEALLOC)
if (size >= malloc_sizes[INDEX_L3 + 1].cs_size
&& cachep->obj_size > cache_line_size() && size < PAGE_SIZE) {
cachep->obj_offset += PAGE_SIZE - size;
size = PAGE_SIZE;
}
#endif
#endif
* Determine if the slab management is 'on' or 'off' slab.
* (bootstrapping cannot cope with offslab caches so don't do
* it too early on.)
*/
if ((size >= (PAGE_SIZE >> 3)) && !slab_early_init)
// 如果对象大小比较大,设置CFLGS_OFF_SLAB标志
// (PAGE_SIZE >> 3)在X86下是512
/*
* Size is large, assume best to place the slab management obj
* off-slab (should allow better packing of objs).
*/
flags |= CFLGS_OFF_SLAB;
size = ALIGN(size, align);
left_over = calculate_slab_order(cachep, size, align, flags);
// cachep->num为每个slab中的对象数
// 为0表示找不到合适的内存slab块大小
printk("kmem_cache_create: couldn't create cache %s.\n", name);
kmem_cache_free(&cache_cache, cachep);
cachep = NULL;
goto oops;
}
// 对齐slab结构本身大小, 大小包括slab头(struct slab), 以及cachep->num个对象
// 的控制量的大小, kmem_bufctl_t其实是一个无符合整数
// typedef unsigned int kmem_bufctl_t
slab_size = ALIGN(cachep->num * sizeof(kmem_bufctl_t)
+ sizeof(struct slab), align);
* If the slab has been placed off-slab, and we have enough space then
* move it on-slab. This is at the expense of any extra colouring.
*/
// 有OFF_SLAB标志而且slab剩余空间比slab本身还大
if (flags & CFLGS_OFF_SLAB && left_over >= slab_size) {
// 将slab参数移到剩余空间中
flags &= ~CFLGS_OFF_SLAB;
left_over -= slab_size;
}
/* really off slab. No need for manual alignment */
slab_size =
cachep->num * sizeof(kmem_bufctl_t) + sizeof(struct slab);
}
// colour_off是根据硬件L1 CACHE元素大小来定
// 是
cachep->colour_off = cache_line_size();
/* Offset must be a multiple of the alignment. */
if (cachep->colour_off < align)
cachep->colour_off = align;
// colour是指在剩余空间中能用的colour_off偏移值的数量
// 表明能放几个整的L1 CACHE元素
cachep->colour = left_over / cachep->colour_off;
// slab控制部分大小
cachep->slab_size = slab_size;
cachep->flags = flags;
cachep->gfpflags = 0;
if (flags & SLAB_CACHE_DMA)
cachep->gfpflags |= GFP_DMA;
// 实际内存缓冲区大小
cachep->buffer_size = size;
cachep->slabp_cache = kmem_find_general_cachep(slab_size, 0u);
/*
* This is a possibility for one of the malloc_sizes caches.
* But since we go off slab only for object size greater than
* PAGE_SIZE/8, and malloc_sizes gets created in ascending order,
* this should not happen at all.
* But leave a BUG_ON for some lucky dude.
*/
BUG_ON(!cachep->slabp_cache);
}
cachep->ctor = ctor;
cachep->dtor = dtor;
cachep->name = name;
// 建立每个CPU各自的cache数据
if (setup_cpu_cache(cachep)) {
__kmem_cache_destroy(cachep);
cachep = NULL;
goto oops;
}
// 将新建的cache块挂接到cache链表
list_add(&cachep->next, &cache_chain);
oops:
if (!cachep && (flags & SLAB_PANIC))
panic("kmem_cache_create(): failed to create slab `%s'\n",
name);
mutex_unlock(&cache_chain_mutex);
unlock_cpu_hotplug();
return cachep;
}
// 该函数可在内核模块中访问
EXPORT_SYMBOL(kmem_cache_create);
* kmem_cache_alloc - Allocate an object
* @cachep: The cache to allocate from.
* @flags: See kmalloc().
*
* Allocate an object from this cache. The flags are only relevant
* if the cache has no available objects.
*/
void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
{
return __cache_alloc(cachep, flags, __builtin_return_address(0));
}
EXPORT_SYMBOL(kmem_cache_alloc);
* kmem_cache_zalloc - Allocate an object. The memory is set to zero.
* @cache: The cache to allocate from.
* @flags: See kmalloc().
*
* Allocate an object from this cache and set the allocated memory to zero.
* The flags are only relevant if the cache has no available objects.
*/
void *kmem_cache_zalloc(struct kmem_cache *cache, gfp_t flags)
{
void *ret = __cache_alloc(cache, flags, __builtin_return_address(0));
if (ret)
memset(ret, 0, obj_size(cache));
return ret;
}
EXPORT_SYMBOL(kmem_cache_zalloc);
// 在内核配置了CONFIG_NUMA时NUMA_BUILD为1,否则为0
static __always_inline void *__cache_alloc(struct kmem_cache *cachep,
gfp_t flags, void *caller)
{
unsigned long save_flags;
void *objp = NULL;
current->flags & (PF_SPREAD_SLAB | PF_MEMPOLICY)))
// 进入此处的可能性比较小
objp = alternate_node_alloc(cachep, flags);
// 主要是进入该函数分配,这个是4下划线的cache_cache
objp = ____cache_alloc(cachep, flags);
/*
* We may just have run out of memory on the local node.
* __cache_alloc_node() knows how to locate memory on other nodes
*/
if (NUMA_BUILD && !objp)
objp = __cache_alloc_node(cachep, flags, numa_node_id());
local_irq_restore(save_flags);
// 实际为objp=objp, 没啥操作
objp = cache_alloc_debugcheck_after(cachep, flags, objp,
caller);
prefetchw(objp);
return objp;
}
static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags)
{
void *objp;
struct array_cache *ac;
// 每个cpu对应的cache数组
ac = cpu_cache_get(cachep);
if (likely(ac->avail)) {
// 当前cache单元空间中有元素,不用重新分配,将缓冲的cache返回
STATS_INC_ALLOCHIT(cachep);
ac->touched = 1;
objp = ac->entry[--ac->avail];
} else {
// 否则新分配cache单元
STATS_INC_ALLOCMISS(cachep);
objp = cache_alloc_refill(cachep, flags);
}
return objp;
}
static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags)
{
int batchcount;
struct kmem_list3 *l3;
struct array_cache *ac;
int node;
node = numa_node_id();
// 每个cpu对应的cache数组
ac = cpu_cache_get(cachep);
retry:
// 一次批量分配的数量, 分配是批量进行, 这样不用每次请求都分配操作一次
batchcount = ac->batchcount;
if (!ac->touched && batchcount > BATCHREFILL_LIMIT) {
/*
* If there was little recent activity on this cache, then
* perform only a partial refill. Otherwise we could generate
* refill bouncing.
*/
batchcount = BATCHREFILL_LIMIT;
}
// 和CPU对应的具体list3链表
l3 = cachep->nodelists[node];
spin_lock(&l3->list_lock);
// 可从共享的数组中获取空间
if (l3->shared && transfer_objects(ac, l3->shared, batchcount))
goto alloc_done;
while (batchcount > 0) {
struct list_head *entry;
struct slab *slabp;
/* Get slab alloc is to come from. */
// 从部分使用的slab链表中获取链表元素
entry = l3->slabs_partial.next;
// 已经到链表头,说明该部分使用的slab链表已经都用完了
// 得从空闲slab链表中找空间了
l3->free_touched = 1;
entry = l3->slabs_free.next;
if (entry == &l3->slabs_free)
// 空闲slab链表也用完了, 整个cache该增加了
goto must_grow;
}
// 获取可用的slab指针
slabp = list_entry(entry, struct slab, list);
check_slabp(cachep, slabp);
check_spinlock_acquired(cachep);
// 从该slab块中批量提取可用的对象数
while (slabp->inuse < cachep->num && batchcount--) {
STATS_INC_ALLOCED(cachep);
STATS_INC_ACTIVE(cachep);
STATS_SET_HIGH(cachep);
// avail记录了实际分配出的对象数
ac->entry[ac->avail++] = slab_get_obj(cachep, slabp,
node);
}
check_slabp(cachep, slabp);
// 把该slab先从所在链表断开
list_del(&slabp->list);
// 根据是否slab中的对象已经用完,将slab挂到全部使用链表或部分使用链表
if (slabp->free == BUFCTL_END)
list_add(&slabp->list, &l3->slabs_full);
else
list_add(&slabp->list, &l3->slabs_partial);
}
// 已经分配了一些对象出去, 减少空闲对象数
l3->free_objects -= ac->avail;
alloc_done:
spin_unlock(&l3->list_lock);
// avail为0, 表示没有可分配的对象了, cache必须增大了
int x;
// 增加cache中内存,增加slab数
x = cache_grow(cachep, flags, node);
ac = cpu_cache_get(cachep);
if (!x && ac->avail == 0) /* no objects in sight? abort */
return NULL;
goto retry;
}
ac->touched = 1;
// 返回对象指针
return ac->entry[--ac->avail];
}
* kmem_cache_free - Deallocate an object
* @cachep: The cache the allocation was from.
* @objp: The previously allocated object.
*
* Free an object which was previously allocated from this
* cache.
*/
// 其实只是__cache_free()的包裹函数
void kmem_cache_free(struct kmem_cache *cachep, void *objp)
{
unsigned long flags;
__cache_free(cachep, objp);
local_irq_restore(flags);
}
EXPORT_SYMBOL(kmem_cache_free);
* Release an obj back to its cache. If the obj has a constructed state, it must
* be in this state _before_ it is released. Called with disabled ints.
*/
static inline void __cache_free(struct kmem_cache *cachep, void *objp)
{
struct array_cache *ac = cpu_cache_get(cachep);
objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0));
return;
// 空闲值小于限值
STATS_INC_FREEHIT(cachep);
// 只是简单将要释放的cache单元添加到空闲单元数组中
// avail增加表示可用对象增加
ac->entry[ac->avail++] = objp;
return;
} else {
// 空闲数大于等于限值
STATS_INC_FREEMISS(cachep);
// 释放一些节点
cache_flusharray(cachep, ac);
// 再将要释放的cache单元添加到空闲单元数组中
// avail增加表示可用对象增加
ac->entry[ac->avail++] = objp;
}
}
* kmem_cache_destroy - delete a cache
* @cachep: the cache to destroy
*
* Remove a struct kmem_cache object from the slab cache.
*
* It is expected this function will be called by a module when it is
* unloaded. This will remove the cache completely, and avoid a duplicate
* cache being allocated each time a module is loaded and unloaded, if the
* module doesn't have persistent in-kernel storage across loads and unloads.
*
* The cache must be empty before calling this function.
*
* The caller must guarantee that noone will allocate memory from the cache
* during the kmem_cache_destroy().
*/
void kmem_cache_destroy(struct kmem_cache *cachep)
{
BUG_ON(!cachep || in_interrupt());
lock_cpu_hotplug();
mutex_lock(&cache_chain_mutex);
/*
* the chain is never empty, cache_cache is never destroyed
*/
// cache的第一个元素cache_cache是静态量,该链表永远不会空
// 从cache链表中删除cache
list_del(&cachep->next);
mutex_unlock(&cache_chain_mutex);
if (__cache_shrink(cachep)) {
slab_error(cachep, "Can't free all objects");
mutex_lock(&cache_chain_mutex);
list_add(&cachep->next, &cache_chain);
mutex_unlock(&cache_chain_mutex);
unlock_cpu_hotplug();
return;
}
synchronize_rcu();
// 释放cache
__kmem_cache_destroy(cachep);
unlock_cpu_hotplug();
}
EXPORT_SYMBOL(kmem_cache_destroy);
static void __kmem_cache_destroy(struct kmem_cache *cachep)
{
int i;
struct kmem_list3 *l3;
for_each_online_cpu(i)
kfree(cachep->array[i]);
// 释放list3中的所有内存
for_each_online_node(i) {
l3 = cachep->nodelists[i];
if (l3) {
kfree(l3->shared);
free_alien_cache(l3->alien);
kfree(l3);
}
}
// 释放cache本身
kmem_cache_free(&cache_cache, cachep);
}
* kmem_cache_shrink - Shrink a cache.
* @cachep: The cache to shrink.
*
* Releases as many slabs as possible for a cache.
* To help debugging, a zero exit status indicates all slabs were released.
*/
// 只是一个包裹函数
int kmem_cache_shrink(struct kmem_cache *cachep)
{
BUG_ON(!cachep || in_interrupt());
}
EXPORT_SYMBOL(kmem_cache_shrink);
{
int ret = 0, i = 0;
struct kmem_list3 *l3;
// 释放cache中每个CPU对应的空间
drain_cpu_caches(cachep);
for_each_online_node(i) {
// 释放每个节点的list3
l3 = cachep->nodelists[i];
if (!l3)
continue;
// 将slab从slab_free中释放
drain_freelist(cachep, l3, l3->free_objects);
!list_empty(&l3->slabs_partial);
}
return (ret ? 1 : 0);
}
{
struct kmem_list3 *l3;
int node;
check_irq_on();
l3 = cachep->nodelists[node];
if (l3 && l3->alien)
// 释放cache的list3的alien部分
drain_alien_cache(cachep, l3->alien);
}
l3 = cachep->nodelists[node];
if (l3)
// 释放list3的数组空间
drain_array(cachep, l3, l3->shared, 1, node);
}
}
* Remove slabs from the list of free slabs.
* Specify the number of slabs to drain in tofree.
*
* Returns the actual number of slabs released.
*/
static int drain_freelist(struct kmem_cache *cache,
struct kmem_list3 *l3, int tofree)
{
struct list_head *p;
int nr_freed;
struct slab *slabp;
// 从slabs_free链表释放
while (nr_freed < tofree && !list_empty(&l3->slabs_free)) {
p = l3->slabs_free.prev;
if (p == &l3->slabs_free) {
spin_unlock_irq(&l3->list_lock);
goto out;
}
// 获取slab
slabp = list_entry(p, struct slab, list);
#if DEBUG
BUG_ON(slabp->inuse);
#endif
// 将slab从链表中删除
list_del(&slabp->list);
/*
* Safe to drop the lock. The slab is no longer linked
* to the cache.
*/
// 空闲对象数减少一个slab中的对象数
l3->free_objects -= cache->num;
spin_unlock_irq(&l3->list_lock);
// 释放slab
slab_destroy(cache, slabp);
nr_freed++;
}
out:
return nr_freed;
}
static inline void *kmalloc(size_t size, gfp_t flags)
{
if (__builtin_constant_p(size)) {
// 以下是找一个对象大小刚好大于等于size的cache
int i = 0;
#define CACHE(x) \
if (size <= x) \
goto found; \
else \
i++;
#include "kmalloc_sizes.h"
#undef CACHE
{
extern void __you_cannot_kmalloc_that_much(void);
__you_cannot_kmalloc_that_much();
}
found:
// 实际还是通过kmem_cache_alloc来分配内存空间, 因此也是cache
return kmem_cache_alloc((flags & GFP_DMA) ?
malloc_sizes[i].cs_dmacachep :
malloc_sizes[i].cs_cachep, flags);
}
// 通过该函数最后也是由__cache_alloc()函数来分配空间
return __kmalloc(size, flags);
}
// 普通情况下最大是128K, 也就是kmalloc能分配的最大内存量
CACHE(32)
#endif
CACHE(64)
#if L1_CACHE_BYTES < 64
CACHE(96)
#endif
CACHE(128)
#if L1_CACHE_BYTES < 128
CACHE(192)
#endif
CACHE(256)
CACHE(512)
CACHE(1024)
CACHE(2048)
CACHE(4096)
CACHE(8192)
CACHE(16384)
CACHE(32768)
CACHE(65536)
CACHE(131072)
#if (NR_CPUS > 512) || (MAX_NUMNODES > 256) || !defined(CONFIG_MMU)
CACHE(262144)
#endif
#ifndef CONFIG_MMU
CACHE(524288)
CACHE(1048576)
#ifdef CONFIG_LARGE_ALLOCS
CACHE(2097152)
CACHE(4194304)
CACHE(8388608)
CACHE(16777216)
CACHE(33554432)
#endif /* CONFIG_LARGE_ALLOCS */
#endif /* CONFIG_MMU
/* mm/slab.c */
void kfree(const void *objp)
{
struct kmem_cache *c;
unsigned long flags;
return;
local_irq_save(flags);
kfree_debugcheck(objp);
c = virt_to_cache(objp);
debug_check_no_locks_freed(objp, obj_size(c));
__cache_free(c, (void *)objp);
local_irq_restore(flags);
}
EXPORT_SYMBOL(kfree);
Linux内核中内存cache的实现【转】的更多相关文章
- (笔记)Linux内核中内存相关的操作函数
linux内核中内存相关的操作函数 1.kmalloc()/kfree() static __always_inline void *kmalloc(size_t size, gfp_t flags) ...
- Linux内核中的Cache段
Linux内核中的Cache段 原文地址:http://blogold.chinaunix.net/u2/85263/showart_1743693.html 最近移植LEON3的内核时,了解了一些简 ...
- Linux 内核的文件 Cache 管理机制介绍
Linux 内核的文件 Cache 管理机制介绍 http://www.ibm.com/developerworks/cn/linux/l-cache/ 1 前言 自从诞生以来,Linux 就被不断完 ...
- linux内核申请内存函数
kmap函数: 把某块高端内存映射到页表,然后返回给用户一个填好vitual字段的page结构 建立永久地址映射,不是简单的返回virtual字段的pageioremap: 驱动程序 ...
- Linux 内核的文件 Cache 管理机制介绍-ibm
https://www.ibm.com/developerworks/cn/linux/l-cache/ 1 前言 自从诞生以来,Linux 就被不断完善和普及,目前它已经成为主流通用操作系统之一,使 ...
- KSM剖析——Linux 内核中的内存去耦合
简介: 作为一个系统管理程序(hypervisor),Linux® 有几个创新,2.6.32 内核中一个有趣的变化是 KSM(Kernel Samepage Merging) 允许这个系统管理程序通 ...
- Linux内核中常见内存分配函数(二)
常用内存分配函数 __get_free_pages unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order) __get_f ...
- Linux内核中常见内存分配函数(一)
linux内核中采 用了一种同时适用于32位和64位系统的内存分页模型,对于32位系统来说,两级页表足够用了,而在x86_64系 统中,用到了四级页表. * 页全局目录(Page Global Dir ...
- Linux内核中常见内存分配函数【转】
转自:http://blog.csdn.net/wzhwho/article/details/4996510 1. 原理说明 Linux内核中采用了一种同时适用于32位和64位系统的内存分页 ...
随机推荐
- jQuery全选反选实例
1. $('#tb:checkbox').each(function(){ 每次都会执行 全选-取消操作,注意$('#tb :checkbox').prop('checked',true); tb后面 ...
- [洛谷P3261][JLOI2015]城池攻占
题目大意:有$n$个点的树,第$i$个节点有一个权值$h_i$,$m$个骑士,第$i$个骑士攻击力为$v_i$,一个骑士可以把从它开始的连续的父亲中比它小的节点攻破,攻破一个节点可以把攻击力加或乘一个 ...
- BZOJ1040 骑士 【环套树 树形dp】
1040: [ZJOI2008]骑士 Time Limit: 10 Sec Memory Limit: 162 MB Submit: 5611 Solved: 2166 [Submit][Stat ...
- "HK"日常之冻结术
在那遥远的MSDN上,有那么一只被隐藏的函数,它掌管着Windows内核威力不容小觑~ 本教程仅作为学习研究,禁止其他用途! 富强.民主.文明.和谐, 自由.平等.公正.法治, 爱国.敬业.诚信.友善 ...
- JS传递中文参数出现乱码的解决办法
一.window.open() 乱码: JS中使用window.open("url?param="+paramvalue)传递参数出现乱码,提交的时候,客户端浏览器URL中显示参数 ...
- BZOJ2434: [NOI2011]阿狸的打字机(AC自动机+dfs序+树状数组)
[NOI2011]阿狸的打字机 题目链接:https://www.luogu.org/problemnew/show/P2414 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. ...
- 宽度搜索(BFS)中求最短路径问题理解记录
借助ACM1242题深入理解迷宫类最短路径搜索并记录路径长度的问题及解决方法:这是初次接触优先队列,尤其是不知道该怎样去记忆在结构体重自定义大小比较的符号方向,很容易混淆符号向哪是从大到小排列,向哪是 ...
- centos上tensorflow一键安装脚本
鉴于tensorflow在centos上安装相当麻烦,特地制作了一个脚本方便以后移植到其它机器上,脚本含有其它python常用包: #! /bin/bash sudo yum install -y ...
- Java设计模式の装饰者模式
目录 一.问题引入 二.设计原则 三.用装饰者模式解决问题 四.装饰者模式的特点 五.装饰者模式的定义 六.装饰者模式的实现 七.java.io包内的装饰者模式 一.问题引入 咖啡店的类设计: 一个饮 ...
- java项目环境搭建
开发java项目时,由于涉及到版权问题,最好使用开源.免费的软件.比如eclipse. 此外,一个web的java项目涉及到jdk.tomcat等,插件还可能用到svn插件.maven插件. 建议进入 ...