(笔记)Linux内核学习(九)之内核内存管理方式
一 页
内核把物理页作为内存管理的基本单位;内存管理单元(MMU)把虚拟地址转换为物理
地址,通常以页为单位进行处理。MMU以页大小为单位来管理系统中的也表。
32位系统:页大小4KB
64位系统:页大小8KB
内核用相应的数据结构表示系统中的每个物理页:
<linux/mm_types.h>
struct page {}
内核通过这样的数据结构管理系统中所有的页,因此内核判断一个页是否空闲,谁有拥有这个页
,拥有者可能是:用户空间进程、动态分配的内核数据、静态内核代码、页高速缓存……
系统中每一个物理页都要分配这样一个结构体,进行内存管理。
二 区
Linux内存寻址存在问题:
一些硬件只能用某些特定的内存来执行DMA(直接内存访问)
一些体系结构其内存的物理寻址范围必须你寻址范围大得多。这样导致一些内存不能永久映射到内核空间上。
通常32位Linux内核地址空间划分0~3G为用户空间,3~4G为内核空间。当内核模块代码或线程访问内存时,
代码中的内存地址都为逻辑地址,而对应到真正的物理内存地址,需要地址一对一的映射。因此内核空间地址为3~4G,
最多只能映射到1G空间的内存,超出1G大小的内存将如何去问呢!
由于存在上述条件的限制。Linux将内核空间地址划分为三个区:
ZONE_DMA、ZONE_NORMAL和ZONE_HIGHMEM。
ZONE_HIGHMEM即为高端内存,这就是内存高端内存概念的由来。
在x86结构中,三种类型的区域如下:
ZONE_DMA 内存开始的16MB
ZONE_NORMAL 16MB~896MB
ZONE_HIGHMEM 896MB ~ 结束
同样每个区包含众多页,形成不同内存池,按照用途进行内存分配。
用相应的数据结构来表示区:
<linux/mmzone.h>
struct zone {}
三 获取页/内存
static inline struct page *alloc_pages(gfp_t gfp_mask, unsigned int order)
该函数分配2的order次方个连续的物理页,返回指向第一个页的page结构体指针。
void *page_address(const struct page *page)
返回指向给定物理页当前所在的逻辑地址
extern unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);
extern unsigned long get_zeroed_page(gfp_t gfp_mask);
释放:
extern void __free_pages(struct page *page, unsigned int order);
extern void free_pages(unsigned long addr, unsigned int order);
内存的分配可能失败,内存的释放要准确!
1 kmalloc
kmalloc()函数与用户空间malloc一组函数类似,获得以字节为单位的一块内核内存。
void *kmalloc(size_t size, gfp_t flags)
void kfree(const void *objp)
分配内存物理上连续。
gfp_t标志:表明分配内存的方式。如:
GFP_ATOMIC:分配内存优先级高,不会睡眠
GFP_KERNEL:常用的方式,可能会阻塞。
2 vmalloc
void *vmalloc(unsigned long size)
void vfree(const void *addr)
vmalloc()与kmalloc方式类似,vmalloc分配的内存虚拟地址是连续的,而物理地址则无需连续,与用户空间分配函数一致。
vmalloc通过分配非连续的物理内存块,在修正页表,把内存映射到逻辑地址空间的连续区域中,虚拟地址是连续的。
是否必须要连续的物理地址和具体使用场景有关。在不理解虚拟地址的硬件设备中,内存区都必须是连续的。
通过建立页表转换成虚拟地址空间上连续,肯定存在一些消耗,带来性能上影响。
所以通常内核使用kmalloc来申请内存,在需要大块内存时使用vmalloc来分配。
四 slab层
内核中经常进行内存的分配和释放。为了便于数据的频繁分配和回收,通常建立一个空
闲链表——内存池。当不使用的已分配的内存时,将其放入内存池中,而不是直接释放掉。
Linux内核提供了slab层来管理内存的分配和释放。
频繁分配和回收必然导致内存碎片,缓存他们.
slab层得设计实现
slab层把不同的对象划分为所谓的高速缓存组。每个高速缓存组存放不同类型的对象。高速缓存划分为slab,
slab由一个或多个物理上连续的页组成。每个slab处于三种状态之一:满,部分满,空。
高速缓存,slab,对象之间的关系:
与传统的内存管理模式相比, slab 缓存分配器提供了很多优点。首先,内核通常依赖于对小对象的分配,
它们会在系统生命周期内进行无数次分配。slab 缓存分配器通过对类似大小的对象进行缓存而提供这种功能,
从而避免了常见的碎片问题。slab 分配器还支持通用对象的初始化,从而避免了为同一目而对一个对象重复
进行初始化。最后,slab 分配器还可以支持硬件缓存对齐和着色,这允许不同缓存中的对象占用相同的缓存行,
从而提高缓存的利用率并获得更好的性能。
slab数据结构和接口:
每个高速缓存用kmem_cache结构来表示:
struct kmem_cache {
struct kmem_list3 **nodelists;
……
}
缓存区包含三种slab:满,未满,空闲
struct kmem_list3 {
struct list_head slabs_partial; /* partial list first, better asm code */
struct list_head slabs_full;
struct list_head slabs_free;
……
};
每一个slab包含多个对象:
struct slab {
struct list_head list;
unsigned long colouroff;
void *s_mem; /* including colour offset */
unsigned int inuse; /* num of objs active in slab */
kmem_bufctl_t free;
unsigned short nodeid;
};
相关接口:mm/slab.c
内核函数 kmem_cache_create 用来创建一个新缓存。这通常是在内核初始化时执行的,或者在首次加载内核模块时执行。
struct kmem_cache *kmem_cache_create (
const char *name,
size_t size,
size_t align,
unsigned long flags,
void (*ctor)(void *))
name 参数定义了缓存名称,proc 文件系统(在 /proc/slabinfo 中)使用它标识这个缓存。
size 参数指定了为这个缓存创建的对象的大小,
align 参数定义了每个对象必需的对齐。
flags 参数指定了为缓存启用的选项:
kmem_cache_create 的部分选项(在 flags 参数中指定)
SLAB_RED_ZONE 在对象头、尾插入标志,用来支持对缓冲区溢出的检查。
SLAB_POISON 使用一种己知模式填充 slab,允许对缓存中的对象进行监视(对象属对象所有,不过可以在外部进行修改)。
SLAB_HWCACHE_ALIGN 指定缓存对象必须与硬件缓存行对齐。
ctor 和 dtor 参数定义了一个可选的对象构造器和析构器。构造器和析构器是用户提供的回调函数。当从缓存中分配新对象时,可以通过构造器进行初始化。
要从一个命名的缓存中分配一个对象,可以使用 kmem_cache_alloc 函数。
void kmem_cache_alloc( struct kmem_cache *cachep, gfp_t flags );
这个函数从缓存中返回一个对象。注意如果缓存目前为空,那么这个函数就会调用 cache_alloc_refill 向缓存中增加内存。
kmem_cache_alloc 的 flags 选项与 kmalloc 的
cachep:所建立的缓存区
flags参数:
GFP_USER 为用户分配内存(这个调用可能会睡眠)。
GFP_KERNEL 从内核 RAM 中分配内存(这个调用可能会睡眠)。
GFP_ATOMIC 使该调用强制处于非睡眠状态(对中断处理程序非常有用)。
GFP_HIGHUSER 从高端内存中分配内存。
五 高端内存的映射
永久映射:可能会阻塞
映射一个给定的page结构到内核地址空间:
void *kmap(struct page *page)
解除映射:
void kunmap(struct page *page)
临时映射:不会阻塞
void *kmap_atomic(struct page *page)
六 分配函数的选择
l 连续的物理页:kmalloc或者低级页分配器
l 高端内存分配:alloc_pages 指向page结构指针,不是逻辑地址指针。再通过kmap()把高端地址内存映射到内核的逻辑地址空间。
l 无需连续物理地址:vmalloc 虚拟地址连续物理地址可能不连续,相对存在性能损失
l 频繁创建和销毁很多较大数据结构:建立slab缓存区,提高对象分配和回收性能。
Linux高端内存:
http://ilinuxkernel.com/?p=1013
Linux slab 分配器剖析:
https://www.ibm.com/developerworks/cn/linux/l-linux-slab-allocator/
(笔记)Linux内核学习(九)之内核内存管理方式的更多相关文章
- 十天学Linux内核之第三天---内存管理方式
原文:十天学Linux内核之第三天---内存管理方式 昨天分析的进程的代码让自己还在头昏目眩,脑子中这几天都是关于Linux内核的,对于自己出现的一些问题我会继续改正,希望和大家好好分享,共同进步.今 ...
- Linux内核学习笔记——内核内存管理方式
一 页 内核把物理页作为内存管理的基本单位:内存管理单元(MMU)把虚拟地址转换为物理 地址,通常以页为单位进行处理.MMU以页大小为单位来管理系统中的也表. 32位系统:页大小4KB 64位系统:页 ...
- 24小时学通Linux内核之内存管理方式
昨天分析的进程的代码让自己还在头昏目眩,脑子中这几天都是关于Linux内核的,对于自己出现的一些问题我会继续改正,希望和大家好好分享,共同进步.今天将会讲诉Linux如何追踪和管理用户空间进程的可用内 ...
- 菜鸟学习Cocos2d-x 3.x——内存管理
菜鸟学习Cocos2d-x 3.x——内存管理 2014-12-10 分类:Cocos2d-x / 游戏开发 阅读(394) 评论(6) 亘古不变的东西 到现在,内存已经非常便宜,但是也不是可以 ...
- iOS学习17之OC内存管理
1.内存管理的方式 1> iOS应用程序出现Crash(闪退),90%的原因是因为内存问题. 2> 内存问题 野指针异常:访问没有所有权的内存,如果想要安全的访问,必须确保空间还在 内存泄 ...
- iOS学习之Object-C语言内存管理
一.内存管理的方式 1.iOS应用程序出现Crash(闪退),90%的原因是因为内存问题. 2.内存问题: 1)野指针异常:访问没有所有权的内存,如果想要安全的访问,必须 ...
- linux驱动程序之电源管理之新版linux系统设备架构中关于电源管理方式的变更
新版linux系统设备架构中关于电源管理方式的变更 based on linux-2.6.32 一.设备模型各数据结构中电源管理的部分 linux的设备模型通过诸多结构体来联合描述,如struct d ...
- glusterfs 内存管理方式
glusterfs中的内存管理方式: 首先来看看glusterfs的内存管理结构吧: struct mem_pool { struct list_head list; int hot_count; i ...
- windows内存管理方式以及优缺点
Windows内存管理方式:页式管理,段式管理,段页式管理 页式管理 将各进程的虚拟空间(逻辑地址)划分为若干个长度相等的页,业内管理把内存空间(物理内存)按照页的大小划分为片或者页面,从而实现了离散 ...
随机推荐
- 用c#开发微信 (6) 微渠道 - 推广渠道管理系统 1 基础架构搭建
我们可以使用微信的“生成带参数二维码接口”和 “用户管理接口”,来实现生成能标识不同推广渠道的二维码,记录分配给不同推广渠道二维码被扫描的信息.这样就可以统计和分析不同推广渠道的推广效果. 本系统使用 ...
- 在Mac上用自己编译出的DNX运行.NET程序
DNX的全称是.NET Execution Enviroment(.NET执行环境),它是.NET跨平台的一个重要角色.如果你关注.NET的跨平台,一定要关注DNX. 由于Mono 4.0的一个bug ...
- windows下重启mysql
其中第二种方法对我这无效,以后再搞清楚! 一.MYSQL服务 我的电脑——(右键)管理——服务与应用程序——服务——MYSQL——开启(停止.重启动) 二.命令行方式 Windows 1.点击“开始” ...
- [翻译]Bob大叔:反思极限编程
译者注: Bob大叔14年后再次谈论极限编程.极限编程经历了14年的风风雨雨后,Bob大叔将会给它怎么样的定义那? 在我手中拿着的一本白皮薄书,在14年前彻底的改变了软件世界.这本书的标题是解析极限编 ...
- Gradle命令行黑魔法
毫无疑问,现在Gradle已经成为java世界最火的构建工具,风头已经盖过了冗余的ant,落后的maven.Gradle是以Groovy语言编写的一套构建脚本的DSL,由于Groovy语法的优雅,所以 ...
- java.nio.BufferOverflowException. Check the Eclipse log for stack trace.
这个错误错了几次,必须做个标记 解决方法非常的简单: 最新的19版本会在你的项目下建立一个依赖包 Android Dependencies,在eclipse中右键这个文件夹,在Build Path选项 ...
- 相对路径获取项目文件 及报错 No mapping found for HTTP request with URI XXX in DispatcherServlet with name ‘springmvc’解决方法
首先一点,WebRoot目录下的文件是都可以通过浏览器输入路径,直接读取到的 例如这样: 而WebRoot下面WEB-INF是无法浏览器输入路径直接读取的. 因为是受保护的. 如果jsp读取一个图片的 ...
- ios 项目里常用的宏
NSLog(@"__func__ : %s", __func__);//oc测试环境,打印文件名,方法名 NSLog(@"__FUNCTION__ : %s" ...
- sql server创建备份计划
对于备份计划,在sql server中微软提供了相应的功能集,通过Maintenance Plans向导可以对数据库进行相关维护工作. 通过下图的向导,可以进行如定期备份和清除工作. 前提是安装介质包 ...
- 開啟apache的日誌功能,但是不記錄.js;.css;.jpg;.ico;.png等訪問記錄
維護web伺服器最重要的就是要每天都關注網站的訪問日誌,但是每天面對幾百兆的日誌文件實在是非常頭大,所以可以從根源上給日誌減肥一下,讓日誌只記錄對自己有用的內容就變得非常重了. Nginx伺服器要修改 ...