linux内核申请内存函数
kmap函数:
把某块高端内存映射到页表,然后返回给用户一个填好vitual字段的page结构
建立永久地址映射,不是简单的返回virtual字段的page
ioremap:
驱动程序无法直接访问io物理地址,所以ioremap是为了使将其映射到虚拟内存,然后直接像访问内存那样访问io
当开启了CONFIG_HIGHMEM时,能操作大于896M的RAM
所以当物理内存大于896M且内核开启了CONFIG_HIGHMEM,ioremap传入的phys_addr参数可以为高端的ram地址
kmalloc则是slab机制来分配内核对象
kzalloc zeroes the memory before returning a pointer
kcalloc allocates memory for an array, it is not a replacement for kmalloc :
void *kcalloc(size_t n, size_t size, gfp_t flags)
vmalloc is the same as kmalloc, except it allocates memory that is only virtually contiguous. The underling physical memory can be discontiguous.
Linux内核中内存的管理不像在内核外这么简单。和用户空间最大的不同是内核的内从空间不像用户空间那么容易得到,并不是总能轻易的得到想要的内存。
页:
内核最基本的内存管理单元就是页(page),因为MMU管理的内存基本单位是page,其维护着提供虚拟地址到物理地址转换的页表。
内核使用如下数据结构表述page:
struct page {
unsigned long flags; //the status of the page,eg if the page is dirty,is locked
atomic_t _count; //the references to this page
atomic_t _mapcount;
unsigned long private;
struct address_space *mapping;
pgoff_t index;
struct list_head lru;
void *virtual;//the page's virtual space
};
需要注意的page数据结构是对机器中所有物理内存的描述并关心页中具体的数据,它只关心诸如page是否空闲,谁在占用这个page等等。
区:
内核将整个内存分为三个区(zone)。
ZONE_DMA--可进行DMA的内存空间,在x86中是低于16M的地址空间
ZONE_NOMAL--在x86中是16M-896M的空间,这部分空间是永久直接映射到内核地址空间的
ZONE_HIGHMEM--动态映射的地址空间
为什么要分区呢?因为在一些体系(如x86)中只有部分内存是可以直接映射的,对x86在896M以上的内存都是动态映射的,所以内核对内存分区描述显得必要,DMA分区是能够进行DMA操作的内存空间。
内核页分配接口:
内核提供若干以page为分配单元的内存分配函数。
struct page * alloc_pages(gfp_t gfp_mask, unsigned int order);
分配2的order次方个连续的页面,返回指向第一个page的指针。当然在实际中我们一般针对分配的内存的虚拟地址进行操作,下面这个
void * page_address(struct page *page);
返回page的逻辑地址指针。
当然为了方便内核也提供直接返回虚拟地址指针的函数,实际就是包装了这两个函数:
unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);
还有直接分配单个page的函数,实际就是order参数为0的版本:
struct page * alloc_page(gfp_t gfp_mask) ;
unsigned long __get_free_page(gfp_t gfp_mask);
如果你想获得的页面全部被初始化为0,内核提供这个调用:
get_zeroed_page(gfp_mask);
工作方式和__get_free_pages相同,除了该函数会将内核空间初始化为0。
这些函数都有相对应的页面释放函数,原型如下:
void __free_pages(struct page *page, unsigned int order) ;
void free_pages(unsigned long addr, unsigned int order) ;
void free_page(unsigned long addr);
更常用的分配接口:
除了原始的以页为单元的内存分配函数,内核还提供更为方便的和C语言中接口类似的分配接口,最常用的就是kmalloc函数:
void * kmalloc(size_t size, gfp_t flags);
该接口返回至少size字节的物理连续的内存空间。用法和c语言malloc函数一样。
当然还有类似free的内存释放函数
void kfree(const void *ptr);
内核还提供vmalloc函数,用法和kmalloc一样,唯一的不同的vmalloc不保证分配的内存是物理连续的。
怎么选择用哪个分配函数呢?大多数情况下,我们需要分配的内存并没有需要是物理连续的,除了外设操作的内存需要内存连续,因为对很多外设来说并没有逻辑内存的概念,他只能看到和操作物理内存。其他情况下,我们并没有一定要使用连续物理内存的需要。然而事实是,大多是情况下,内核中还是使用kmalloc来分配内存,这基本上是基于效率考虑。因为vmalloc调用为了使不连续物理内存的逻辑地址连续会有很多附加对页表的操作,所以除了必须(需要使用相当大的内存空间),一般情况直接使用kmalloc函数。
vmalloc也有对应的vfree函数。
gfp_mask参数:
gfp_mask参数可以设置很多值,一下是各个取值的用处(直接引用至LKD):
GFP_ATOMIC The allocation is high priority and must not sleep. This is the flag to use in interrupt handlers, in bottom halves, while holding a spinlock, and in other situations where you cannot sleep.
GFP_NOWAIT Like GFP_ATOMIC, except that the call will not fallback on emergency memory pools. This increases the liklihood of the memory allocation failing.
GFP_NOIO This allocation can block, but must not initiate disk I/O. This is the flag to use in block I/O code when you cannot cause more disk I/O, which might lead to some unpleasant recursion.
GFP_NOFS This allocation can block and can initiate disk I/O, if it must, but it will not initiate a filesystem operation. This is the flag to use in filesystem code when you cannot start another filesystem operation.
GFP_KERNEL This is a normal allocation and might block. This is the flag to use in process context code when it is safe to sleep. The kernel will do whatever it has to do to obtain the memory requested by the caller. This flag should be your default choice.
GFP_USER This is a normal allocation and might block. This flag is used to allocate memory for user-space processes.
GFP_HIGHUSER This is an allocation from ZONE_HIGHMEM and might block. This flag is used to allocate memory for user-space processes.
GFP_DMA This is an allocation from ZONE_DMA. Device drivers that need DMA-able memory use this flag, usually in combination with one of the preceding flags.
使用SLAB缓存分配:
当需要频繁的针对特定数据结构分配和释放内存时,为了避免反复内存分配和释放的开销,Linux内核提供了强大的内存缓存分配策略,即SLAB缓存分配。(实际上kmalloc函数就是建立在slab分配器上的!)
每个slab包含一定数量的对象,即需要被缓存的数据结构,每个slab都有三个状态:full,partial,empty。当试图从slab中分配一个object时,内核优先从partial的slab中获取对象,不行则从empty slab中,如果全部是full则创建一个新的slab。内核中管理slab缓存的组成主要有cache,slab,object.
cache在内核中使用 kmem_cache结构来描述,包含三个链表--—slabs_full, slabs_partial, 以及slabs_empty。这些list中就包含相应状态的slab,slab在内核中的描述如下:
struct slab {
struct list_head list; /* full, partial, or empty list */
unsigned long colouroff; /* offset for the slab coloring */
void *s_mem; /* first object in the slab */
unsigned int inuse; /* allocated objects in the slab */
kmem_bufctl_t free; /* first free object, if any */
};
下列函数可以创建一个新的cache:
struct kmem_cache * kmem_cache_create(const char *name, size_t size,
size_t align, unsigned long flags, void (*ctor)(void *));
各个参数说明如下:
const char *name:cache的名称。
size_t size:cache中需要缓存的object的大小。
size_t align:slab中第一个object的偏移,一般0即可,使用标准对齐方式。
unsigned long flags:可以为缓存分配执行一些附加操作,没有的话直接0即可。
void (*ctor)(void *):cache的构造函数,你可以赋值一个函数地址,当新的page加入cache后一定会执行该构造函数。可以复赋值为NULL。
销毁一个cache时使用
int kmem_cache_destroy(struct kmem_cache *cachep);
内核提供两个函数负责从指定的cache获取和交还内存:
void * kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags);
void kmem_cache_free(struct kmem_cache *cachep, void *objp);
linux内核申请内存函数的更多相关文章
- (笔记)Linux内核中内存相关的操作函数
linux内核中内存相关的操作函数 1.kmalloc()/kfree() static __always_inline void *kmalloc(size_t size, gfp_t flags) ...
- 24小时学通Linux内核之内存管理方式
昨天分析的进程的代码让自己还在头昏目眩,脑子中这几天都是关于Linux内核的,对于自己出现的一些问题我会继续改正,希望和大家好好分享,共同进步.今天将会讲诉Linux如何追踪和管理用户空间进程的可用内 ...
- Linux内核笔记--内存管理之用户态进程内存分配
内核版本:linux-2.6.11 Linux在加载一个可执行程序的时候做了种种复杂的工作,内存分配是其中非常重要的一环,作为一个linux程序员必然会想要知道这个过程到底是怎么样的,内核源码会告诉你 ...
- Linux内核之内存管理
Linux内核之内存管理 Linux利用的是分段+分页单元把逻辑地址转换为物理地址; RAM的某些部分永久地分配给内核, 并用来存放内核代码以及静态内核数据结构; RAM的其余部分称动态内存(dyna ...
- Linux内核中内存cache的实现【转】
Linux内核中内存cache的实现 转自:http://blog.chinaunix.net/uid-127037-id-2919545.html 本文档的Copyleft归yfydz所有,使用 ...
- Linux内核的ioctl函数学习
Linux内核的ioctl函数学习 来源:Linux公社 作者:Linux 我这里说的ioctl函数是在驱动程序里的,因为我不知道还有没有别的场合用到了ioctl, 所以就规定了我们讨论的范围.为什 ...
- Linux内核空间内存申请函数kmalloc、kzalloc、vmalloc
我们都知道在用户空间动态申请内存用的函数是 malloc(),这个函数在各种操作系统上的使用是一致的,对应的用户空间内存释放函数是 free(). 注意:动态申请的内存使用完后必须要释放,否则会造成内 ...
- Linux内核空间内存申请函数kmalloc、kzalloc、vmalloc的区别【转】
转自:http://www.th7.cn/system/lin/201606/167750.shtml 我们都知道在用户空间动态申请内存用的函数是 malloc(),这个函数在各种操作系统上的使用是一 ...
- Linux内核之内存管理完全剖析
linux虚拟内存管理功能 ? 大地址空间:? 进程保护:? 内存映射:? 公平的物理内存分配:? 共享虚拟内存.实现结构剖析 (1)内存映射模块(mmap):负责把磁盘文件的逻辑地址映射到虚拟地 ...
随机推荐
- oracle日期格式数据修改
select * from INVOICE_NEW where ref_no='32308' update INVOICE_NEW set check_d=to_date('2015/11/16', ...
- CSS display:inline和float:left两者区别探讨
本文和大家重点讨论一下CSS display:inline和float:left两者的区别,CSS display是指显示状态,inline表示内联,特点是紧贴着前一个内联元素,通常默认的内联元素有 ...
- Visual C++ 对话框增加菜单栏
1.添加菜单资源 在resourceview视图中右击选择insert,添加一个菜单资源IDR_MENU1,同时设定好响应的菜单项,例 如: 菜单1 ...
- 如何根据w3wp.exe的进程pid查看是哪个应用程序池
如何根据w3wp.exe的进程pid查看是哪个应用程序池? 根据iisapp 查看PID所对应的IIS应用程序池及详细介绍: 从IIS6.0可以在IIS中架设多个站点并给每个站点指定不同的应用程序池, ...
- informix 查看数据库空间名
查看bhrs库的空间名 onstat -d 导出一个表 的结构 dbschema -d bhrs -t infotrans > xxx.sql 微网点 报表已经上线 cbs.sql 提交,生产 ...
- 一步步学习ASP.NET MVC3 (2)——入门程序
请注明转载地址:http://www.cnblogs.com/arhat 在上一节中,我们只是简单的介绍了什么是MVC及MVC的运行原理.而本节呢,主要来实现下一ASP.NET MVC3的开发流程,并 ...
- .net faq
http://www.indiabix.com/technical/dotnet/ http://www.codeproject.com/Articles/637480/Csharp-and-ASP- ...
- 【单片机通信协议】CAN总线基础知识
CAN总线基础知识(一) 1.1 CAN总线是什么? CAN(Controller Area Network)是ISO国际标准化的串行通信协议.广泛应用于汽车.船舶等.具有已经被大家认可的高性能和可靠 ...
- <五> jQuery 效果
显示隐藏 $("selector").show(speed, callback) $("selector").hide"(speed, callbac ...
- [转载]C# 判断字符是否中文还是英文
private static bool IsHanZi(string ch) { byte[] byte_len = System.Text.Encoding.Default.GetBytes(ch) ...