Copyright: 该文章版权由潘云登所有。可在非商业目的下任意传播和复制。

对于商业目的下对本文的任何行为需经作者同意。


kmalloc

#include <linux/slab.h>

void *kmalloc(size_t size, int flags);

void kfree(const void *ptr);

使用kmalloc可以获得以字节为单位的一块内核内存,它不对所获取的内存空间清零。这个函数返回一个指向内存块的指针,其内存块至少要有size大小。所分配的内存区在物理上是连续的。在出错时,它返回NULL。因此,在调用kmalloc()后,必须检查返回的是不是NULL。由kmalloc分配的内存,使用kfree方法进行释放。

kmalloc的第一个参数是要分配块的大小,第二个参数是分配器标志。这个标志在<linux/gfp.h>文件中声明,可以分为三类:行为修饰符、区修饰符以及类型标识。行为修饰符表示内核应当如何分配所需的内存,主要有:

__GFP_WAIT    分配器可以休眠

__GFP_HIGH    分配器可以访问紧急事件缓冲池

__GFP_IO       分配器可以启动磁盘I/O

__GFP_FS       分配器可以启动文件系统I/O

区修饰符表示从哪里分配内存:可用于DMA的内存(__GFP_DMA)、常规内存以及高端内存(__GFP_HIGHMEM)。类型标志组合了行为修饰符和区修饰符,将各种可能用到的组合归纳为不同类型,简化了修饰符的使用。因此,最常使用的flags参数为GFP_KERNEL和GFP_ATOMIC。后者用在中断处理程序或其它运行于进程上下文之外的代码中,这时kmalloc方法不会休眠。

#include <linux/gfp.h>

#define GFP_KERNEL         (__GFP_WAIT | __GFP_IO | __GFP_FS)

#define GFP_ATOMIC        (__GFP_HIGH)

实际上,kmalloc是建立在后面介绍的后备高速缓存之上的。因此,内核只能分配一些预定义的、固定大小的字节数组。根据当前体系结构使用的页面大小,kmalloc能处理的最小内存块是32或者64。如果希望代码具有完整的可移植性,则不应该分配大于128KB的内存。

示例:

char *buf;

buf = kmalloc(BUF_SIZE, GFP_ATOMIC);

if (!buf)

/* 内存分配出错! */

kfree(buf);


后备高速缓存

分配和释放数据结构是所有内核中最普遍的操作之一。为了便于数据的频繁分配和回收,内核提供了后备高速缓存机制,称为“slab分配器”。slab分配器实现的高速缓存具有kmem_cache_t类型,可通过调用kmem_cache_create创建。

#include <linux/slab.h>

kmem_cache_t *kmem_cache_create(const char *name, size_t size,

size_t offset,

unsigned long flags,

void (*constructor)(void *, kmem_cache_t *, unsigned long flags),

void (*destructor)(void *, kmem_cache_t *, unsigned long flags));

参数name存放高速缓存的名字。size是高速缓存中每个元素的大小。offset是高速缓存中第一个对象的偏移,用来确保在页内进行特定的对齐,一般取0。flags是一个位掩码,用来控制高速缓存的行为。constructor和destructor为高速缓存的构造和析构函数,分别在新页追加到高速缓存和从高速缓存中删去页时调用,通常取NULL。kmem_cache_create在成功时返回一个指向所创建高速缓存的指针,否则,返回NULL。在创建高速缓存后,使用kmem_cache_alloc从中分配内存对象。释放一个内存对象时使用kmem_cache_free。要销毁一个高速缓存,则调用kmem_cache_destroy。

void *kmem_cache_alloc(kmem_cache_t *cache, int flags);

void kmem_cache_free(kmem_cache_t *cache, const void *obj);

int kmem_cache_destroy(kmem_cache_t *cache);

示例:

kmem_cache_t *task_struct_cachep;

/*创建高速缓存,SLAB_PANIC标志在分配失败时提醒slab层,

如果没有提供SLAB_PANIC 标志,必须自己检查返回值*/

task_struct_cachep = kmem_cache_create("task_struct",

sizeof(struct task_struct),

ARCH_MIN_TASKALIGN,

SLAB_PANIC,

NULL,

NULL);

/*分配内存对象*/

struct task_struct *tsk;

tsk = kmem_cache_alloc(task_struct_cachep, GFP_KERNEL);

if (!tsk)

return NULL;

/*释放内存对象*/

kmem_cache_free(task_struct_cachep, tsk);

/*撤销高速缓存*/

int err;

err = kmem_cache_destroy(task_struct_cachep);

if (err)

/*撤销高速缓存出错*/


分配页

如果模块需要分配大块的内存,使用面向页的分配技术会更好些。分配页面可以使用下面的函数:

#include <linux/gfp.h>

unsigned long get_zeroed_page(unsigned int gfp_mask);

unsigned long __get_free_page(unsigned int gfp_mask);

unsigned long __get_free_pages(unsigned int gfp_mask, unsigned int order);

它们返回内存区域第一个字节的指针。其中,get_zeroed_page将分配所得的页面清零。参数gfp_mask为分配器标志,与kmaloc中的一样。参数order是要分配的页面数的以2为底的对数。当用字节表示内存大小时,需要使用get_order函数进行转换,而不应该对页面大小进行任何假设,如:

#include <asm/page.h>

/*驱动程序需要16KB空间*/

/* get_order的参数必须是2的幂*/

int order = get_order(16*1024);

buf = get_free_pages(GFP_KERNEL, order);

当程序不再需要使用页面时,可以使用下列函数进行释放:

void free_page(unsigned long addr);

void free_pages(unsigned long addr, unsigned long order);

示例:

unsigned long page;

page = __get_free_pages(GFP_KERNEL, 3);

if (!page) {

/*没有足够的内存,你必须处理这种错误! */

return ENOMEM;

}

/* 'page'现在指向8个连续页中第1个页的地址*/

free_pages(page, 3);


vmalloc

#include <linux/vmalloc.h>

void * vmalloc(unsigned long size);

void vfree(void *addr);

vmalloc函数的工作方式类似于kmalloc,只不过前者分配的内存虚拟地址是连续的,而物理地址则无需连续。它通过分配非连续的物理内存块,再修改页表,把内存映射到逻辑地址空间的连续区域中。通过vmalloc获得的页必须一个一个地进行映射,效率不高,因此,只在不得已(一般是为了获得大块内存)时使用。vmalloc函数返回一个指针,指向逻辑上连续的一块内存区,其大小至少为size。在发生错误时,函数返回NULL。vmalloc可能睡眠,因此,不能从中断上下文中进行调用,也不能从其它不允许阻塞的情况下调用。要释放通过vmalloc所获得的内存,应使用vfree函数。

示例:

char *buf;

buf = vmalloc(16 * PAGE_SIZE); /*获得16页*/

if (!buf)

/*错误,不能分配内存*/

vfree(buf);

内存分配方法 kmalloc()、vmalloc()、__get_free_pages()的更多相关文章

  1. linux内存分配方法总结【转】

    转自:http://www.bkjia.com/Linuxjc/443717.html 内存映射结构: 1.32位地址线寻址4G的内存空间,其中0-3G为用户程序所独有,3G-4G为内核占有. 2.s ...

  2. C语言内存分配方法。

    当C程序运行在操作系统上时,操作系统会给每一个程序分配一定的栈空间. 堆为所有程序共有的,需要时需要申请访问. 一.栈 局部变量.函数一般在栈空间中. 运行时自动分配&自动回收:栈是自动管理的 ...

  3. C++的STL中vector内存分配方法的简单探索

    STL中vector什么时候会自动分配内存,又是怎么分配的呢? 环境:Linux  CentOS 5.2 1.代码 #include <vector> #include <stdio ...

  4. Android内存管理(5)*官方教程:Logcat内存日志各字段含义,查看当前内存快照,跟踪记录内存分配,用adb查看内存情况时各行列的含义,捕获内存快照的3种方法,如何让程序暴漏内存泄漏的方法

    Investigating Your RAM Usage In this document Interpreting Log Messages                 内存分析日志中各消息的含 ...

  5. Linux内核中常见内存分配函数【转】

    转自:http://blog.csdn.net/wzhwho/article/details/4996510 1.      原理说明 Linux内核中采用了一种同时适用于32位和64位系统的内存分页 ...

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

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

  7. C++STL内存管理方法(g++版)

    STL作为C++的经典作品,一直备受人们关注.本文主要介绍STL的内存管理策略. 早期的STL内存管理 第一次接触STL源码是看侯捷先生的<STL源码剖析>,此书通俗易懂,剖析透彻,是极佳 ...

  8. memcache内存分配机制

    memcached的内存分配没有用到c语言中自带的malloc函数,因为这个函数分配内存的时候效率很低,对于这种要求快速响应,对效率要求非常高的缓存软件来说非常不合适. memcached用的是自己的 ...

  9. 转: Linux C 动态内存分配 malloc及相关内容 .

    一.malloc()和free()的基本概念以及基本用法: 1.函数原型及说明: void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针 ...

随机推荐

  1. iOS多线程编程Part 3/3 - GCD

    前两部分介绍了NSThread.NSRunLoop和NSOperation,本文聊聊2011年WWDC时推出的神器GCD.GCD: Grand Central Dispatch,是一组用于实现并发编程 ...

  2. sqlserver 2008 卸载时提示 “重新启动计算机”失败

    问题:sqlserver 2008 卸载时提示 “重新启动计算机”失败 解决办法: 1.打开注册表:开始->运行: regedit 2.找到HKEY_LOCAL_MACHINE\SYSTEM\C ...

  3. 【转】KM匹配题集

    转自:http://blog.csdn.net/shahdza/article/details/7779324 [HDU]2255 奔小康赚大钱 模板题★1533 Going Home 模板题★242 ...

  4. vc6命令行编译工程方法

    查vc++ 6.0 的 msdn找到下面的命令: msdev FileName [/MAKE "ProjectName – ConfigName | ALL"] [/REBUILD ...

  5. Unity3D IOS IPhone添加Admob的方法

    原地址:http://dong2008hong.blog.163.com/blog/static/4696882720140403119293/ 首先阅读官方文档https://developers. ...

  6. 【面试题004】c/c++字符串,替换空格

      一,c/c++字符串 1.C/C++中每个字符串都以字符’\0‘作为结尾,这样我们就能很方便地找到字符串的最后尾部. 由于这个原因每个字符串都有一个额外的开销,注意字符串越界的问题: 2.C/C+ ...

  7. C# 面向对象之概念理解(2)

    委托 如果对象A为了满足某个请求,而寻求另一个对象B的帮助,这被称作是A对B的委托. 对象间的委托,和现实世界中人与人之间的委托一样:如果你“那位”要求你在他外出公干期间帮忙助剪草坪,而你转而雇佣邻居 ...

  8. java基础知识回顾之java Thread类学习(七)--java多线程通信等待唤醒机制(wait和notify,notifyAll)

    1.wait和notify,notifyAll: wait和notify,notifyAll是Object类方法,因为等待和唤醒必须是同一个锁,不可以对不同锁中的线程进行唤醒,而锁可以是任意对象,所以 ...

  9. Android ImageButton的背景(图片)大小

    使用ImageButton的background属性,而不用src属性. 然后使用width和height进行调整.

  10. .NET framework 4.0安装失败怎么办

    开始——运行——输入cmd——回车——在打开的窗口中输入net stop WuAuServ   开始——运行——输入%windir%找到有个叫SoftwareDistribution的文件夹,把它重命 ...