[TZ]内存与IO访问(3)--内存操作

本文探讨Linux内存动态申请,包括用户进程和内核空间的内存分配,如malloc、kmalloc、__get_free_pages等。还涉及虚拟地址与物理地址的转化,以及IO端口和IO内存访问,讲解了ioremap和mmap在设备映射中的作用。此外,文章提及驱动程序如何申请和释放IO资源,以及内存管理技术如slab和内存池。
摘要由CSDN通过智能技术生成

其中一些概念可以参考第一篇《地址、MMU、内存管理相关概念
转载请注明原文地址:http://blog.csdn.net/ts_dchs/article/details/50241887

空间申请,地址转换关系:
malloc
(image source: http://blog.chinaunix.net/uid-20528014-id-315801.html )

注意:主要描述环境是Linux

1 内存申请释放

下面会提到的内存申请:

  • malloc - free: 用户空间,逻辑空间连续 ( +relloc +valloc)
  • kmalloc - kfree: 内核空间,物理连续,常规内存
  • __get_free_pages - free_pages: 内核空间,物理连续,常规内存
  • vmalloc - vfree: 内核空间,物理不连续,虚拟连续,会使TLB抖动,性能降低,高端内存。
  • slab: kmem_cache_create - kmem_cache_destory

1 用户进程空间内存动态申请

malloc()申请的空间在heap上,需要申请者用free()释放。注意尽量成对出现,避免内存泄漏。注:C Linux的malloc常用brk()mmap()系统调用实现。
++原型++:extern void *malloc(unsigned int num_bytes) (stdlib.h in Linux)(malloc.h in windows)
通过void *将返回的指针转化成任意类型,所以分配后常要进行强制类型转换在分配给相应类型的指针。
malloc()返回指针可能是NULL也就是失败,需要在开辟空间的时候加以判断。另外,malloc()只负责映射分配不负责初始化,内容不一定是0.

++原型++:extern void *realloc(void *mem_address, unsigned int newsize)
realloc()malloc()分配方式相同,不过会重新调整原来的空间。如果新空间比原来空间大,会先看直接扩展注册是否可行,不可行则分配新的逻辑地址,拷贝数据,释放原来空间。如果新空间更小可能会数据丢失。

在GNU系统中,malloc或realloc返回的内存块地址都是8的倍数(如果是64位系统,则为16的倍数)。如果你需要更大的粒度,要使用memalign或valloc。

++原型++:void * memalign(size_t boundary, size_t size)
分配以boundary倍数为边界的内存块。且boundary必须是2的幂。

++原型++:void * valloc(size_t size)
利用memalign来分配,不过boundary设定好是page大小。memalign(getpagesize(), size)

2 内核空间内存动态申请

kmalloc()
manual link
申请内存位于物理内存映射区,物理上也连续(对需要DMA的设备很重要)。和真实物理地址只有一个固定的offset。在设备驱动程序或者内核模块中动态开辟内存使用。返回的是线性地址。

++原型++:void *kmalloc(size_t size, int flags);(linux/slab.h)
size是大小,flag是标志,GFP_KERNEL表示在内核空间进程中申请内存。其底层依赖__get_free_pages()实现。使用这个flag后,如果不能满足,进程会睡眠等待页,可能会引起阻塞。因此不能在++中断上下文,spin lock++中使用GFP_KERNEL申请内存。
在++中断处理函数,tasklet,内核定时器++非进程上下文不能阻塞,应该用GFP_ATOMIC申请内存,不存在空闲会直接返回。
相应其他标志位定义于:include/linux/gfp.h。
kfree()释放空间。

*kmalloc最大只能开辟128kB-16B(128k = 32*PAGESIZE),16个字节是被页描述符结构占用了。内存映射的I/O口,寄存器或者是硬件设备的RAM(如显存)一般占用F0000000以上的地址空间。默认最小32KB。
*CONFIG_LARGE_ALLOCS选项开启最大可分配32MB
*开辟的空间可以通过flag控制在DMA Zone或者HIGHMEM Zone中。

kmalloc()用于物理连续内核态小内存分配,get_free_page分配整页的地址。。

__get_free_pages()
Linux Kernel最底层使用的获取空间的方法。底层以page的2^n为单位管理空闲内存,所以内存页的申请是以page为单位。
get_zeroed_page(unsigned int flags);指向一个已经清零的新page。
__get_free_page(unsigned int flags);(是page不是pages)指向新页但不清零,实际上是用了order为0的一个函数。

++原型++:__get_free_pages(unsigned int flags, unsigned int order);(linux/gfp.h)
获取多个pages数量是2^order,不清零。order最大是10或11,硬件相关。(4KB * 1024 =4MB Space)
/proc/buddyinfo 中有系统中每个内存区中的每个 order 有多少块可用,形如

Node 0, zone Normal 1027 339 ...

代表NUMA节点0(不是NUMA则只有0号),常规内存,2^0*PAGESIZE大小的块有1027个,2^1*PAGESIZE大小的块有339个以此类推。如果有11个数字,则order最大值为10,即能分配的最大空间为2^10*PAGESIZE(4KB)=4MB.

*前面三个函数的实现其实是调用了alloc_pages(),该函数可以在用户空间,也可以在内核空间使用。返回struct page *
释放:
void free_page(unsigned long addr);
void free_pages(unsigned long addr, unsigned long order); 特别注意order前后要一致。

*kmalloc和get_free_page都在Kernel的常规内存做线性映射,所以得到的线性地址addr - PAG

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值