Linux内核中常见内存分配函数

1.      原理说明

Linux内核中采 用了一种同时适用于32位和64位系统的内 存分页模型,对于32位系统来说,两级页表足够用了,而在x86_64系 统中,用到了四级页表,如图2-1所示。四级页表分别为:

l         页全局目录(Page Global Directory)

l         页上级目录(Page Upper Directory)

l         页中间目录(Page Middle Directory)

l         页表(Page Table)

    页全局目录包含若干页上级目录的地址,页上级目录又依次包含若干页中间目录的地址,而页中间目录又包含若干页表的地址,每一个页表项指 向一个页框。Linux中采用4KB大小的 页框作为标准的内存分配单元。

 

多级分页目录结构

1.1.      伙伴系统算法

    在实际应用中,经常需要分配一组连续的页框,而频繁地申请和释放不同大小的连续页框,必然导致在已分配页框的内存块中分散了许多小块的 空闲页框。这样,即使这些页框是空闲的,其他需要分配连续页框的应用也很难得到满足。

    为了避免出现这种情况,Linux内核中引入了伙伴系统算法(buddy system)。把所有的空闲页框分组为11个 块链表,每个块链表分别包含大小为12481632641282565121024个连续页框的页框块。最大可以申请1024个连 续页框,对应4MB大小的连续内存。每个页框块的第一个页框的物理地址是该块大小的整数倍。

    假设要申请一个256个页框的块,先从256个页框的链表中查找空闲块,如果没有,就去512个 页框的链表中找,找到了则将页框块分为2256个 页框的块,一个分配给应用,另外一个移到256个页框的链表中。如果512个页框的链表中仍没有空闲块,继续向1024个页 框的链表查找,如果仍然没有,则返回错误。

    页框块在释放时,会主动将两个连续的页框块合并为一个较大的页框块。

1.2.      slab分 配器

    slab分配器源于 Solaris 2.4 的 分配算法,工作于物理内存页框分配器之上,管理特定大小对象的缓存,进行快速而高效的内存分配。

    slab分配器为每种使用的内核对象建立单独的缓冲区。Linux 内核已经采用了伙伴系统管理物理内存页框,因此 slab分配器直接工作于伙伴系 统之上。每种缓冲区由多个 slab组成,每个 slab就是一组连续的物理内存页框,被划分成了固定数目的对象。根据对象大小的不同,缺省情况下一个 slab 最多可以由 1024个页框构成。出于对齐 等其它方面的要求,slab 中分配给对象的内存可能大于用户要求的对象实际大小,这会造成一定的 内存浪费。

2.      常用内存分配函数

2.1.      __get_free_pages

    unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)

 

    __get_free_pages函数是最原始的内存分配方式,直接从伙伴系统中获取原始页框,返回值为第一个页框的起始地址。__get_free_pages在实现上只是封装了alloc_pages函 数,从代码分析,alloc_pages函数会分配长度为1<<order的 连续页框块。order参数的最大值由include/linux/Mmzone.h文 件中的MAX_ORDER宏决定,在默认的2.6.18内 核版本中,该宏定义为10。也就是说在理论上__get_free_pages函 数一次最多能申请1<<10 * 4KB也就是4MB的 连续物理内存。但是在实际应用中,很可能因为不存在这么大量的连续空闲页框而导致分配失败。在测试中,order10时分配成功,order11则返回错误。

2.2.      kmem_cache_alloc

    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))

    void *kmem_cache_alloc(struct kmem_cache *c, gfp_t flags)

 

    kmem_cache_create/ kmem_cache_alloc是基于slab分配器的一种内存分配方式,适用于反复分配释放同一大小内存块的场合。首先用kmem_cache_create创建一个高速缓存区域,然后用kmem_cache_alloc从 该高速缓存区域中获取新的内存块。 kmem_cache_alloc一次能分配的最大内存由mm/slab.c文件中的MAX_OBJ_ORDER宏 定义,在默认的2.6.18内核版本中,该宏定义为5, 于是一次最多能申请1<<5 * 4KB也就是128KB的 连续物理内存。分析内核源码发现,kmem_cache_create函数的size参数大于128KB时会调用BUG()。测试结果验证了分析结果,用kmem_cache_create分 配超过128KB的内存时使内核崩溃。

2.3.      kmalloc

    void *kmalloc(size_t size, gfp_t flags)

 

    kmalloc是内核中最常用的一种内存分配方式,它通过调用kmem_cache_alloc函 数来实现。kmalloc一次最多能申请的内存大小由include/linux/Kmalloc_size.h的 内容来决定,在默认的2.6.18内核版本中,kmalloc一 次最多能申请大小为131702B也就是128KB字 节的连续物理内存。测试结果表明,如果试图用kmalloc函数分配大于128KB的内存,编译不能通过。

2.4.      vmalloc

    void *vmalloc(unsigned long size)

 

    前面几种内存分配方式都是物理连续的,能保证较低的平均访问时间。但是在某些场合中,对内存区的请求不是很频繁,较高的内存访问时间也 可以接受,这是就可以分配一段线性连续,物理不连续的地址,带来的好处是一次可以分配较大块的内存。图3-1表 示的是vmalloc分配的内存使用的地址范围。vmalloc对 一次能分配的内存大小没有明确限制。出于性能考虑,应谨慎使用vmalloc函数。在测试过程中, 最大能一次分配1GB的空间。

 

Linux内核部分内存分布

2.5.      dma_alloc_coherent

    void *dma_alloc_coherent(struct device *dev, size_t size,

ma_addr_t *dma_handle, gfp_t gfp)

    DMA是一种硬件机制,允许外围设备和主存之间直接传输IO数据,而不需要CPU的参与,使用DMA机制能大幅提高与设备通信的 吞吐量。DMA操作中,涉及到CPU高速缓 存和对应的内存数据一致性的问题,必须保证两者的数据一致,在x86_64体系结构中,硬件已经很 好的解决了这个问题, dma_alloc_coherent__get_free_pages函数实现差别不大,前者实际是调用__alloc_pages函 数来分配内存,因此一次分配内存的大小限制和后者一样。__get_free_pages分配的内 存同样可以用于DMA操作。测试结果证明,dma_alloc_coherent函 数一次能分配的最大内存也为4M

2.6.      ioremap

    void * ioremap (unsigned long offset, unsigned long size)

    ioremap是一种更直接的内存“分配”方式,使用时直接指定物理起始地址和需要分配内存的大小,然后将该段 物理地址映射到内核地址空间。ioremap用到的物理地址空间都是事先确定的,和上面的几种内存 分配方式并不太一样,并不是分配一段新的物理内存。ioremap多用于设备驱动,可以让CPU直接访问外部设备的IO空间。ioremap能映射的内存由原有的物理内存空间决定,所以没有进行测试。

2.7.      Boot Memory

    如果要分配大量的连续物理内存,上述的分配函数都不能满足,就只能用比较特殊的方式,在Linux内 核引导阶段来预留部分内存。

2.7.1.       在内核引导时分配内存

    void* alloc_bootmem(unsigned long size)

    可以在Linux内核引导过程中绕过伙伴系统来分配大块内存。使用方法是在Linux内核引导时,调用mem_init函数之前 用alloc_bootmem函数申请指定大小的内存。如果需要在其他地方调用这块内存,可以将alloc_bootmem返回的内存首地址通过EXPORT_SYMBOL导 出,然后就可以使用这块内存了。这种内存分配方式的缺点是,申请内存的代码必须在链接到内核中的代码里才能使用,因此必须重新编译内核,而且内存管理系统 看不到这部分内存,需要用户自行管理。测试结果表明,重新编译内核后重启,能够访问引导时分配的内存块。

2.7.2.       通过内核引导参数预留顶部内存

    Linux内核引导时,传入参数“memsize”保留顶部的内存区间。比如系统有256MB内 存,参数“mem248M”会预留顶部的8MB内存,进入系统后可以调用ioremap(0xF8000000x800000)来申请这段内存。

3.      几种分配函数的比较

 

 

分配原理

最大内存

其他

__get_free_pages

直接对页框进行操作

4MB

适用于分配较大量的连续物理内存

kmem_cache_alloc

基于slab机制实现

128KB

适合需要频繁申请释放相同大小内存块时使用

kmalloc

基于kmem_cache_alloc实现

128KB

最常见的分配方式,需要小于页框大小的内存时可以使用

vmalloc

建立非连续物理内存到虚拟地址的映射

 

物理不连续,适合需要大内存,但是对地址连续性没有要求的场合

dma_alloc_coherent

基于__alloc_pages实现

4MB

适用于DMA操 作

ioremap

实现已知物理地址到虚拟地址的映射

 

适用于物理地址已知的场合,如设备驱动

alloc_bootmem

在启动kernel时,预留一段内存,内核看不见

 

小于物理内存大小,内存管理要求较高

 

   注:表中提到的最大内存数据来自CentOS5.3 x86_64系统,其他系统和体系结构会有不同

 

原文地址 http://blog.csdn.net/wzhwho/archive/2009/12/13/4996510.aspx

Linux复习题综合练习及答案仅选择题 1、Linux的第二块硬盘的第一个分区应该表示为:() A.  /hda1              B.  /hdb1             C.   /hdba             D.  /hda2 2、在Linux中有关IDE设备命名编号正确的有(      ) A. sda   第一个 IDE 控制器,主设备         B. sdb   第二个 IDE 控制器,次设备C.  hda   第二个 IDE 控制器,主设备           D. hda   第一个 IDE 控制器,主设备 3、利用命令find查找当前目录下的名称尾为.c的文件,并将结果输出到标准输出的命令是(      ) A. find . -name "?.c" –print         B. find . -name "#.c" –print C. find . -name "!*.c" –print        D. find . -name "*.c" –print 4、启动运行级别3代表什么:() A.  关闭系统                                                 B.  单用户管理模式 C.  无网络功能的多用户模式             D.  带有网络功能的多用户模式 5、为了将当前目录下的归档文件myftp.tgz解压缩到/tmp目录下,我们可以使用(      ) A. tar xvzf myftp.tgz -C /tmp        B. tar xvzf myftp.tgz -R /tmp C. tar vzf myftp.tgz -X /tmp         D. tar xvzf myftp.tgz /tmp 6、怎样新建一个新文件:() A. mk hello.c             B. rm hello.c  C. touch hello.c   D. new hello.c 7、下面哪些命令可以分页显示大文本文件:(    ) A.  more                     B.  cat C.  type                      D.  less 8、  ls –al 命令列出下面的文件列表,问那一行代表是链接文件。() A. -rw-------  2 hel-s  users   56  sep 09 11:05  hello B. -rw-------  2 hel-s  users   56  sep 09 11:05  goodbey C. drwx-----  1 hel   users  1024  sep 10 08:10  zhang D. lrwx-----  1 hel  users  2024    sep 12 08:12   cheng       9、以下哪几种是vi的工作模式(      )(多选) A. 命令模式         B. 删除模式        C. 编辑模式      D. 末行模式 10、临时注销一个用户,可以直接修改/etc/shadow文件,即在该用户口令前加(      ) A. !            B.#                C.%                D.* 11、启动X-Windows命令是(      ) A. Start          B.startx           C. begin           D. beginx 12、安装Linux系统对磁盘分区的要求是( ) A 至少有一个磁盘分区 B 至少有两个磁盘分区 C 至少有三个磁盘分区 D 至少有四个磁盘分区 13、下面哪个文件包含了主机名到ip地址的映射关系() A. /etc/hostname               B. /etc/hosts C. /etc/resolv.conf              D. /etc/networks 14、在Linux系统,默认的shell是什么:() A.  bash               B. ash C.   csh                D. gnush 15、Pwd命令的功能是() A 设置用户的口令 B 显示用户的口令 C 相当于Windows命令行里输入C D命令 D 相当于在windows命令行里输入dir命令 16、当一个目录作为一个挂载点被使用后,该目录上的原文件( ) A、 被永久删除 B、被隐藏,待挂载设备卸载后恢复 C、 被放入回收站 D、被隐藏,待计算机重新启动后恢复 17、执行命令“chmod o+rw myfile”后,myfile文件的权限变化为( ) A、 同组用户可读写myfile文件         B、其他用户可读写myfile文件 C、 所有用户都可读写myfile文件      D、文件所有者读写myfile文件 18、tar命令可以进行文件的( ) A、压缩、归档和解压缩 B、压缩和解压缩 C、压缩和归档 D、归档和解压缩 19、负责执行防火墙规则的服务(守护进程)是( ) A、 iptables B、network C、security D、xinetd 20、使用vi编辑文本只读时,保存并退出的命令是?(单选题) A :w!        B :q!       C   :wq       D   :e! 21、当一个文件属性为drwxrwxrwt,则这个文件的权限是什么样的?(多选题) A: 任何用户皆可读取、可写入         B: root 可以删除该目录的文件 C: 给普通用户以文件所有者的特权     D:文件拥有者有权删除该目录的文件 22、什么命令用来查看硬盘被占用了多少空间和剩余多少空间? (单选题) A : du   B: df    C: free   D: vmstat 23、Linux 使用者的帐号、密码与群组的名称文件放在哪些文件里?(多选题) A: /etc/passwd                  B:   /etc/shadow C: /etc/group                     D:   /etc/users 24、暂停某用户帐号可以使用如下哪些方法?(多选题) A.把/etc/passwd文件中该用户信息字段前加# B.passwd -1[用户名] C.将/etc/passwd该用户信息shell字段改成/sbin/nologin D.passwd -u[用户名] 。。。。。。。。。。。。。。。。。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值