技术标签: memory 平台 linux x86 user
Linux 处理内存分配通过创建一套固定大小的内存对象池.
分配请求被这样来处理, 进入一个持有足够大的对象的池子并且将整个内存块递交给请求者.
驱动开发者应当记住的一件事情是, 内核只能分配某些预定义的, 固定大小的字节数组.
如果你请求一个任意数量内存, 你可能得到稍微多于你请求的, 至多是 2 倍数量.
同样, 程序员应当记住 kmalloc 能够处理的最小分配是 32或者 64字节, 依赖系统的体系所使用的页大小.
kmalloc 能够分配的内存块的大小有一个上限. 这个限制随着体系和内核配置选项而变化.
如果你的代码是要完全可移植,它不能指望可以分配任何大于 128 KB.
如果你需要多于几个 KB,但是,有个比 kmalloc更好的方法来获得内存,__get_free_pages(), 直接分配页。
在设备驱动程序或者内核模块中动态开辟内存,不是用malloc,而是kmalloc ,vmalloc,或者用get_free_pages直接申请页。
释放内存用的是kfree,vfree,或free_pages. kmalloc函数返回的是虚拟地址(线性地址).
kmalloc特殊之处在于它分配的内存是物理上连续的,这对于要进行DMA的设备十分重要.
而用vmalloc分配的内存只是线性地址连续,物理地址不一定连续,不能直接用于DMA.
注意kmalloc最大只能开辟128k-16,16个字节是被页描述符结构占用了。
内存映射的I/O口,寄存器或者是硬件设备的RAM(如显存)一般占用F0000000以上的地址空间,在驱动程序中不能直接访问,要通过kernel函数vremap获得重新映射以后的地址。
另外,很多硬件需要一块比较大的连续内存用作DMA传送。这块内存需要一直驻留在内存,不能被交换到文件中去。但是kmalloc最多只能开辟大小为32XPAGE_SIZE的内存,一般的PAGE_SIZE=4kB,也就是128kB的大小的内存。
kmalloc内存分配和malloc相似,除非被阻塞否则他执行的速度非常快,而且不对获得空间清零.
说明:在用kmalloc申请函数后,要对齐清零,通常用memset()函数对申请的内存进行清零。
kmalloc函数原型:#include<linux/slab.h>
Void *kmalloc(size_t size, gfp_t flags);
第一个参数是要分配的块的大小
第二个参数是分配标志(flags).
返回一个指向该内存块的指针, 出错时,返回NULL。除非没有足够的内存,否则内核总能分配成功。
例:
struct dog *p;
p = kmalloc(sizeof(struct dog), GFP_KERNEL);
if(!p){
//处理内存分配错误时的应对措施。
}
最常用的是GFP_KERNEL,表示内存分配是运行在内核空间的进程执行的。
内存分配最终总是调用get_free_pages来实现的,这就是GFP前缀的由来。
GFP_ATOMIC
用来从中断处理和进程上下文之外的其他代码中分配内存. 从不睡眠.
如果在进程上下文中如:中断处理程序、tasklet以及内核定时器中这种情况下,current进程不该睡眠,驱动程序该使用GFP_ATOMIC.
GFP_KERNEL
内核内存的正常分配. 可能睡眠.
使用GFP_KERNEL容许kmalloc在分配空闲内存时候如果内存不足容许把当前进程睡眠以等待。因此这时分配函数必须是可重入的。
GFP_USER
用来为用户空间页来分配内存; 它可能睡眠.
GFP_HIGHUSER
如同 GFP_USER, 但是从高端内存分配, 如果有. 高端内存在下一个子节描述.
__GFP_FS
表示分配器可以启动文件系统I/O。
__GFP_IO表示分配器可以启动磁盘I/O.
GFP_NOFS,GFP_NOIO
这个标志功能如同 GFP_KERNEL, 但是它们增加限制到内核能做的来满足请求. 一个 GFP_NOFS 分配不允许进行任何文件系统调用, 而 GFP_NOIO 根本不允许任何 I/O 初始化. 它们主要地用在文件系统和虚拟内存代码, 那里允许一个分配睡眠, 但是递归的文件系统调用会是一个坏注意.
2.1 上面列出的这些分配标志可以是下列标志的相或来作为参数, 这些标志改变这些分配如何进行:
__GFP_DMA
这个标志要求分配在能够 DMA 的内存区. 确切的含义是平台依赖的并且在下面章节来解释.
__GFP_HIGHMEM
这个标志指示分配的内存可以位于高端内存.
__GFP_COLD
这个标志请求一个"冷"页, 告诉分配器应该使用高速缓存中快要被淘汰出去的页。
__GFP_NOWARN
这个标志作用:当一个分配无法满足时,阻止内核来发出警告(使用 printk ),即不打印失败警告。
__GFP_HIGH
这个标志标识了一个高优先级请求, 它被允许来消耗甚至被内核保留给紧急状况的最后的内存页.
2.2 下面三个标志修改分配器如何动作, 当它有困难满足一个分配.__GFP_REPEAT
意思是" 更尽力些尝试" 通过重复尝试 -- 但是分配可能仍然失败.
__GFP_NOFAIL
标志告诉分配器不要失败; 它尽最大努力来满足要求. 使用 __GFP_NOFAIL 是强烈不推荐的; 可能从不会有有效的理由在一个设备驱动中使用它.
__GFP_NORETRY
告知分配器立即放弃如果得不到请求的内存.
2.2 内存区段 --- ZONE:
__GFP_DMA和__GFP_HIGHMEM的使用与平台相关。
Linux把内存分成3个区段:可用于DMA的内存、常规内存、以及高端内存。
X86平台上ISA设备DMA区段是内存的前16MB,而PCI设备无此限制。
内存区后面的机制在 mm/page_alloc.c 中实现, 而内存区的初始化在平台特定的文件中, 常常在 arch 目录树的 mm/init.c。
2.3. 什么时候用什么标志:
进程上下文,可以睡眠 --- 使用 GFP_KERNEL
进程上下文,不可以睡眠 --- 使用 GFP_ATOMIC
中断处理程序 --- 使用 GFP_ATOMIC
软中断 --- 使用 GFP_ATOMIC
tasklet --- 使用 GFP_ATOMIC
需要用于DMA 的内存,可以睡眠 --- 使用 (GFP_KERNEL | GFP_DMA)
需要用于DMA的内存,不可以睡眠 --- 使用 (GFP_ATOMIC | GFP_DMA)
3. kfree()
void kfree(const void *ptr);
释放由kmalloc()分配的内存块。 ptr是kmalloc的返回值指针。
例子:
#define BUF_SIZE 1024
char *buf;
buf = kmalloc(BUF_SIZE, GFP_KERNEL)
if(!buf){
/* 内存分配出错处理程序 */
}
...
kfree(buf);
4.1 void *vmalloc(unsigned long size);
该函数返回一个指针,指向虚拟内存中连续的一块内存区。
其大小至少为size。
发生错误时返回NULL。
该函数可能睡眠,因此,不能再中断上下文中进行调用,也不能在不允许阻塞的情况下调用。
4.2 void *vfree(const void *addr);
这个函数会释放从 addr 开始的内存块,其中addr 是由之前 vmalloc()分配的内存块地址。
这个函数也可能睡眠,因此不能在中断上下文中调用。
例子:
char *buf;
buf = vmalloc(16 * PAGE_SIZE);
if(!buf){
/* 错误处理代码 */
}
...
vfree(buf);
• vmalloc()与 kmalloc()都可用于分配内存.
• kmalloc()分配的内存处于3GB~high_memory之 间,这段内核空间与物理内存的映射一一对应
•vmalloc()分配的内存在 VMALLOC_START~4GB之间,这段非连续内 存区映射到物理内存也可能是非连续的
• 在内核空间中调用kmalloc()分配连续物理空间,而调用vmalloc()分配非物理连续空间。
• 把kmalloc()所分配内核空间中的地址称为内核逻辑地址
• 把vmalloc()分配的内核空间中的地址称 为内核虚拟地址
• vmalloc()在分配过程中须更新内核页表
总结:
1.kmalloc和vmalloc分配的是内核的内存,malloc分配的是用户的内存
2.kmalloc保证分配的内存在物理上是连续的,kmalloc()分配的内存在0xBFFFFFFF-0xFFFFFFFF以上的内存中,driver一般是用它来完成对DS的分配,更适合于类似设备驱动的程序来使用;
3.vmalloc保证的是在虚拟地址空间上的连续,vmalloc()则是位于物理地址非连续,虚地址连续区,起始位置由VMALLOL_START来决定,一般作为交换区、模块的分配。用户空间多用这个函数来分配内存。
3.kmalloc能分配的大小有限,vmalloc和malloc能分配的大小相对较大(因为vmalloc还可以处理交换空间)。
4.内存只有在要被DMA访问的时候才需要物理上连续,vmalloc比kmalloc要慢
5.vmalloc使用的正确场合是分配一大块,连续的,只在软件中存在的,用于缓冲的内存区域。不能在微处理器之外使用。
6.vmalloc 中调用了 kmalloc (GFP—KERNEL),因此也不能应用于原子上下文。
7.kmalloc和 kfree管理内核段内分配的内存,这是真实地址已知的实际物理内存块。
8.vmalloc对应于vfree,分配连续的虚拟内存,但是物理上不一定连续。
9.kmalloc分配内存是基于slab,因此slab的一些特性包括着色,对齐等都具备,性能较好。物理地址和逻辑地址都是连续的
10. kmalloc 通常分配以字节为单位的一段连续内存,如果需要更大的,如以页为单位的内存,需要使用alloc_pages()/__get_free_pages()等以页问操作单位的函数。
摘要:研究了一种主动、自然的室内环境中未知物体的检测问题。提出了一种同时利用颜色和深度信息的视觉显著性方案,以唤起机器系统在三维场景中显著位置检测未知物体的兴趣。在突出位置的三维点被选择为种子点,用三维形状生成对象假设。我们在马尔可夫随机场(MRF)上对三维场景的体素进行多类标记,结合对象假设和三维形状的线索。MRF的结果进一步细化合并标记的对象,它们之间的空间连接和颜色直方图之间有很高的相关性。...
1.求下面程序段的时间复杂度 x = 91; y = 100; while (y > 0) if (x > 100) { x = x - 10; y--; } else x++;1.求下面程序段的时间复杂度 x = 91; y = 100; while (y > 0) { if (x > 100...
解决ImportError: cannot import name ‘imread’ from 'scipy.misc’在调试faster-rcnn.pytorch1.6代码时遇到问题解决ImportError: cannot import name ‘imread’ from ‘scipy.misc’解决方法:将from scipy.misc import imread换成from imageio import imread学习记录使用,如有侵权请联系删除,谢谢!!...
也经常写架构设计文档,但是以前都是采用的野路子,参考别人的经验,然后自己摸索出一些规律,没有怎么正儿八经去遵循某个理论体系。理论来源有两个:一本薄薄的英文原版书,书名好像就是软件架构;另外就是RUP了。我记得2000年前,还不怎么提什么架构设计,到了2000年以后,这个概念慢慢开始火起来。最近,在同时给业务部门和技术部门写解决方案和架构文档,又重新产生了一些疑问,正巧接触到一些企业架构理论方面的知识,觉得跟自己以前的实践还是有一些印证的。正好也学习学习:了解企业架构,可以从下面这篇经典的文章入手,里面将四种
Visual Studio Code 是一个免费的开发工具,比较轻量,很多人都会用。如果你还没有安装 Python 扩展的话,在第一次使用 Visual Studio Code 导入 Python 项目,将会提示你安装 Python 扩展。安装扩展在 VSC 的右下角,将会提示你安装 Python 扩展。单击 install 进行安装即可。下面的图显示扩展正在进行安装。如果还需要其他一些扩展需要进行安装的话,按照提示进行安装即可。有可能能够在控制台...
最近服务器连接数据库总是超时,查看报错日志显示java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 60001ms.所以怀疑是数据库连接数不够的问题.而导致数据库连接数不够,原因有很多,总结了一下,大致有两方面配置问题:1.H...
查找某个节点的路径的方法通常有两种,一种是递归算法,另一种是非递归算法定义树节点class TreeNode{ constructor(value){ this.value = value; this.left = null; this.right = null; }}构建树// 构建树let root = new TreeNode(1);root.left = new TreeNode(2);root.right = n.
送给程序员的励志名言精选1、信念和目标,必须永远洋溢在程序员内心。2、IF(BOOL 学习= =FALSE)BOOL 落后=TRUE;不断的学习,我们才能不断的前进。3、编程中我们会遇到多少挫折?表放弃,沙漠尽头必是绿洲。4、如果调试一个程序让你很苦恼,千万不要放弃,成功永远在拐角之后,除非你走到拐角。5、作为一个真正的程序员,首先应该尊重编程,热爱你所写下的程序,他是你的伙伴,而不是工具。6、程...
本文完成RTX3090Windows+Ubuntu双系统配置 ,并配置深度学习环境硬件环境为RTX3090+Z590主板,64GB RAM,2TB固态,8TB存储Ubuntu系统版本为:Ubuntu 20.04.3 LTS深度学习环境:cuda11.0.4;cudnn8.2.4;pytorch1.9
本质是参数化类型可以用在类,接口,方法的创建中 类——泛型类.note public class GenericCla<T,P> { public T method1(T t){ return t; } public P method2(P p){ return p; } public <P> P method3(){ return null; }} 接口——泛
第一题:现有这么一批数据,现要求出: 每个用户截止到每月为止的最大单月访问次数和累计到该月的总访问次数 三个字段的意思: 用户名,月份,访问次数 A,2015-01,5 A,2015-01,15 B,2015-01,5 A,2015-01,8 B,2015-01,25 A,2015-01,5 A,2015-02,4 A,2015-02,6 ...