Chinaunix首页 | 论坛 | 博客
  • 博客访问: 98961
  • 博文数量: 28
  • 博客积分: 1435
  • 博客等级: 上尉
  • 技术积分: 265
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-26 11:40
文章分类

全部博文(28)

文章存档

2017年(1)

2012年(1)

2011年(6)

2010年(20)

我的朋友

分类: LINUX

2010-05-19 20:11:48



小引:

很久很久以前:一个叫做Mark Hemment的哥儿们写了Slab。在接下来的一些年里,其他人对Slab进行了完善。一年半以前,SLOB问世了。SLOB的目标是针对嵌入式系统 的,主要是适用于那些内存非常有限的系统,比如32MB以下的内存,它不太注重large smp系统,虽然最近在这方面有一些小的改进。几个月之前,SLUB闪亮登场。它基本上属于对Slab的重设计(redesign),但是代码更少,并且 能更好的适应large NUMA系统。

SLUB被很认为是Slab和Slob的取代者,内核开发人员称其为:more SMP-friendly SLUB allocator。显然,在桌面平台上的多核心处理器也能从中受益。

在研究SLUB之前,先说说SLAB。众所周知,操作系统进行内存分配的时候,是以页为单位进行的,也可以称为内存块或者堆。但是内核对象远小于页的大 小,而这些对象在操作系统的生命周期中会被频繁的申请和释放,并且实验发现,这些对象初始化的时间超过了分配内存和释放内存的总时间,所以需要一种更细粒 度的针对内核对象的分配算法,于是SLAB诞生了:

SLAB缓存已经释放的内核对象,以便下次申请时不需要再次初始化和分配空间,类似对象池的概念。并且没有修改通用的内存分配算法,以保证不影响大内存块 分配时的性能。

由于SLAB按照对象的大小进行了分组,在分配的时候不会产生堆分配方式的碎片,也不会产生Buddy分配算法中的空间浪费,并且支持硬件缓存对齐来提高 TLB的性能,堪称完美。

但是这个世界上没有完美的算法,一个算法要么占用更多的空间以减少运算时间,要么使用更多的运算时间减少空间的占用。优秀的算法就是根据实际应用情况在这 两者之间找一个平衡点。SLAB虽然能更快的分配内核对象,但是metadata,诸如缓存队列等复杂层次结构占用了大量的内存。

SLUB因此而诞生:

SLUB 不包含SLAB这么复杂的结构。SLAB不但有队列,而且每个SLAB开头保存了该SLAB对象的metadata。SLUB只将相近大小的对象对齐填入 页面,并且保存了未分配的SLAB对象的链表,访问的时候容易快速定位,省去了队列遍历和头部metadata的偏移计算。该链表虽然和SLAB一样是每 CPU节点单独维护,但使用了一个独立的线程来维护全局的SLAB对象,一个CPU不使用的对象会被放到全局的partial队列,供其他CPU使用,平 衡了个节点的SLAB对象。回收页面时,SLUB的SLAB对象是全局失效的,不会引起对象共享问题。另外,SLUB采用了合并相似SLAB对象的方法, 进一步减少内存的占用。

据内核开发人员称,SLUB相对于SLAB有5%-10%的性能提升和减少50%的内存占用(是内核对象缓存占用的,不是全局哦,否则Linux Kernel可以修改主版本号了)。所以SLUB是一个时间和空间上均有改善的算法,而且SLUB完全兼容SLAB的接口,所以内核其他模块不需要修改即 可从SLUB的高性能中受益。SLUB在2.6.22内核中理所当然的替代了SLAB。

下面还有一些有用的链接:
slab:http://www.ibm.com/developerworks/cn/linux/l-linux-slab-allocator/
slob:
slub:

测试代码:

#include <linux/module.h>
#include <linux/slab.h>
#define MY_NAME "lizhijie"
struct people_info
{
    char *name;
    int age;
};

static struct list_head *my_chain;

struct kmem_cache *people_info_cachep;

static void people_info_ctor(void *info)
{
    memset(info,0,sizeof(struct people_info));
}
static int __init my_cache_init(void)
{
    struct people_info *my_info;
    struct kmem_cache *tmp;
    int i=0;

    people_info_cachep=kmem_cache_create("people_info_cache",
            sizeof(struct people_info),
            0,
            SLAB_PANIC|SLAB_RECLAIM_ACCOUNT,
            people_info_ctor);


    my_info=kmem_cache_alloc(people_info_cachep,GFP_KERNEL);
    my_info->name=MY_NAME;
    my_info->age=24;
    
    my_chain=&people_info_cachep->list;
    list_for_each_entry(tmp,my_chain,list)
    {
        if(!tmp->name)
        {
            //NOTE: my_chain here is just a list_head,not kmem_cache.

            my_chain=&tmp->list;
            break;
        }
    }
    list_for_each_entry(tmp,my_chain,list)
    {
        printk("LZJ:%s\n",tmp->name);
        i++;
    }
    printk("LZJ:number of kmem_cache:%d\n",i);


    kmem_cache_free(people_info_cachep,my_info);
    return 0;
}

static void __exit my_cache_exit(void)
{
    kmem_cache_destroy(people_info_cachep);
}

MODULE_AUTHOR("zhijie Li");
MODULE_DESCRIPTION("This is a slab test.");
MODULE_LICENSE("Dual BSD/GPL");
module_init(my_cache_init);
module_exit(my_cache_exit);


注:
    第一个list_for_each_entry是为了找到kmem_cache链表的头指针。头指针是一个struct list_head 指针,不包含在struct kmem_cache中,如果没有这一步,直接从当前的people_info_cachep->list开始遍历,当遍历到那个链表头的时候将会出现问题,因为那时候的list不是包含在struct kmem_cache中的list。
    另外:用list_for_each_entry遍历链表的时候不包含链表头的遍历,因为一般来说,链表头都只是一个”裸“的struct list_head。将遍历不到我们创建的people_info_cachep。

输出结果:
编译之后insmod,执行:
左:dmesg|grep "LZJ"
右:awk 'BEGIN {num=0} {if(NR>2) print $1 num++} END {printf("%d kmem_caches\n",num)}' /proc/slabinfo
[11931.178681] LZJ:people_info_cache
[11931.178685] LZJ:VMBlockInodeCache
[11931.178687] LZJ:blockInfoCache
[11931.178688] LZJ:kmalloc_dma-512
[11931.178690] LZJ:RAWv6
[11931.178692] LZJ:UDPLITEv6
[11931.178693] LZJ:UDPv6
[11931.178695] LZJ:tw_sock_TCPv6
[11931.178697] LZJ:TCPv6
[11931.178698] LZJ:flow_cache
[11931.178700] LZJ:dm_raid1_read_record
[11931.178701] LZJ:kcopyd_job
[11931.178703] LZJ:dm_uevent
[11931.178705] LZJ:dm_rq_target_io
[11931.178706] LZJ:cfq_queue
[11931.178708] LZJ:bsg_cmd
[11931.178710] LZJ:mqueue_inode_cache
[11931.178711] LZJ:fuse_request
[11931.178713] LZJ:fuse_inode
[11931.178715] LZJ:ecryptfs_inode_cache
[11931.178716] LZJ:hugetlbfs_inode_cache
[11931.178718] LZJ:jbd2_revoke_record
[11931.178720] LZJ:journal_head
[11931.178721] LZJ:revoke_record
[11931.178723] LZJ:ext4_inode_cache
[11931.178725] LZJ:ext4_free_block_extents
[11931.178726] LZJ:ext4_alloc_context
[11931.178728] LZJ:ext4_prealloc_space
[11931.178730] LZJ:ext4_system_zone
[11931.178731] LZJ:ext2_inode_cache
[11931.178734] LZJ:ext3_inode_cache
[11931.178736] LZJ:ext3_xattr
[11931.178737] LZJ:dquot
[11931.178739] LZJ:posix_timers_cache
[11931.178740] LZJ:UDP-Lite
[11931.178742] LZJ:UDP
[11931.178743] LZJ:tw_sock_TCP
[11931.178745] LZJ:TCP
[11931.178747] LZJ:sgpool-128
[11931.178748] LZJ:sgpool-64
[11931.178750] LZJ:sgpool-32
[11931.178751] LZJ:sgpool-16
[11931.178753] LZJ:blkdev_queue
[11931.178754] LZJ:blkdev_requests
[11931.178756] LZJ:biovec-256
[11931.178757] LZJ:biovec-128
[11931.178759] LZJ:biovec-64
[11931.178761] LZJ:bip-256
[11931.178762] LZJ:bip-128
[11931.178764] LZJ:bip-64
[11931.178765] LZJ:sock_inode_cache
[11931.178767] LZJ:skbuff_fclone_cache
[11931.178769] LZJ:file_lock_cache
[11931.178770] LZJ:net_namespace
[11931.178772] LZJ:shmem_inode_cache
[11931.178773] LZJ:Acpi-Operand
[11931.178775] LZJ:Acpi-Namespace
[11931.178777] LZJ:taskstats
[11931.178778] LZJ:proc_inode_cache
[11931.178780] LZJ:sigqueue
[11931.178781] LZJ:radix_tree_node
[11931.178783] LZJ:bdev_cache
[11931.178784] LZJ:sysfs_dir_cache
[11931.178786] LZJ:inode_cache
[11931.178787] LZJ:dentry
[11931.178789] LZJ:buffer_head
[11931.178790] LZJ:vm_area_struct
[11931.178792] LZJ:mm_struct
[11931.178793] LZJ:sighand_cache
[11931.178795] LZJ:task_xstate
[11931.178796] LZJ:task_struct
[11931.178798] LZJ:anon_vma
[11931.178800] LZJ:idr_layer_cache
[11931.178801] LZJ:kmalloc-8192
[11931.178803] LZJ:kmalloc-4096
[11931.178804] LZJ:kmalloc-2048
[11931.178806] LZJ:kmalloc-1024
[11931.178807] LZJ:kmalloc-512
[11931.178809] LZJ:kmalloc-256
[11931.178810] LZJ:kmalloc-128
[11931.178811] LZJ:kmalloc-64
[11931.178813] LZJ:kmalloc-32
[11931.178814] LZJ:kmalloc-16
[11931.178816] LZJ:kmalloc-8
[11931.178817] LZJ:kmalloc-192
[11931.178819] LZJ:kmalloc-96
[11931.178821] LZJ:number of kmem_cache:86



people_info_cache0
VMBlockInodeCache1
blockInfoCache2
kmalloc_dma-5123
RAWv64
UDPLITEv65
UDPv66
tw_sock_TCPv67
TCPv68
flow_cache9
dm_raid1_read_record10
kcopyd_job11
dm_uevent12
dm_rq_target_io13
cfq_queue14
bsg_cmd15
mqueue_inode_cache16
fuse_request17
fuse_inode18
ecryptfs_inode_cache19
hugetlbfs_inode_cache20
jbd2_revoke_record21
journal_head22
revoke_record23
ext4_inode_cache24
ext4_free_block_extents25
ext4_alloc_context26
ext4_prealloc_space27
ext4_system_zone28
ext2_inode_cache29
ext3_inode_cache30
ext3_xattr31
dquot32
posix_timers_cache33
UDP-Lite34
UDP35
tw_sock_TCP36
TCP37
sgpool-12838
sgpool-6439
sgpool-3240
sgpool-1641
blkdev_queue42
blkdev_requests43
biovec-25644
biovec-12845
biovec-6446
bip-25647
bip-12848
bip-6449
sock_inode_cache50
skbuff_fclone_cache51
file_lock_cache52
net_namespace53
shmem_inode_cache54
Acpi-Operand55
Acpi-Namespace56
taskstats57
proc_inode_cache58
sigqueue59
radix_tree_node60
bdev_cache61
sysfs_dir_cache62
inode_cache63
dentry64
buffer_head65
vm_area_struct66
mm_struct67
sighand_cache68
task_xstate69
task_struct70
anon_vma71
idr_layer_cache72
kmalloc-819273
kmalloc-409674
kmalloc-204875
kmalloc-102476
kmalloc-51277
kmalloc-25678
kmalloc-12879
kmalloc-6480
kmalloc-3281
kmalloc-1682
kmalloc-883
kmalloc-19284
kmalloc-9685
86 kmem_caches



两者结果一致!
阅读(1288) | 评论(0) | 转发(0) |
0

上一篇:内核radix tree初探

下一篇:libusb介绍及使用

给主人留下些什么吧!~~