内核怎样管理你的内存【转】

转自:http://blog.csdn.net/bullbat/article/details/7311955

 bullbat  译   

     在分析了进程的虚拟地址布局,我们转向内核以及他管理用户内存的机制。下图是gonzo的例子:

       Linux进程在内核中是由task_struct进程描述符实现的,task_struct的mm字段指向内存描述符mm_struct,他是进程的一个内存执行摘要。如上图所示,mm_struct存储了内存各个段的开始和结束地址、进程所使用的内存页面数(rss代表常驻集合大小)、使用的虚拟地址空间总数等等。在内存描述符中我们也可以找到两个用于管理进程内层的字段:虚拟内存集合和页表。Gonzo的内存区域如下图:

       每个虚拟内存区域(VMA)是一个虚拟地址空间上连续的区域;这些区域不会彼此覆盖。Vm_area_struct结构描述了一个内存区域,包括他的开始和技术地址、flags字段指定了他的行为和访问权限,vm_file字段指定了该区域映射的实际文件。一个没有映射文件的VMA成为匿名的。除了内存映射段以外,上面的每个内存段(堆、栈等等)相当于一个单独的VMA。这不是必须的,尽管在x86机器上通常是这样。VMA不会关心他在哪个段里面。

       一个进程的所有VMA以两种方式存储在他的内存描述符中,一种是以链表的方式存放在mmap字段,以开始虚拟地址进行了排序,另一种是以红黑树的方式存放,mm_rb字段为这颗红黑树的根。红黑树可以让内核根据给定的虚拟地址快速地找到内存区域。当我们读取文件/proc/pid_of_process/maps,内核仅仅是通过进程VMA的链接同时打印出每一个。

       在windows中,块EPROCESS基本上是task_struct和mm_struct的结合体。Windows用虚拟地址描述符,或者说VAD,模拟一个VMA;VAD存储在一个AVL树(平衡二叉树)中。你知道有关Windows和Linux的最有趣的事情是什么?那就是他们之间差异很小。

        4GB大小的虚拟地址空间被分为一个个页面。32位的x86处理器支持的页面大小为4KB、2MB和4MB。Linux和windows都使用4KB大小的页面来映射用户空间部分的虚拟地址空间。0~4095字节为页面0,4096~8191字节为页面1等等。VMA的大小必须是一个页面大小的整数倍。下图是4KB页面大小模式的3GB用户空间:

       处理器借助页表将虚拟地址转换为物理地址。每个进程有他自己的页表集合;每当一个进程切换发生,他用户空间的页表也随着切换。Linux在进程的内存描述符中存放了一个pgd字段指向进程的页表。每一个虚拟页面对应与页表中的一个页表入口(PTE),这个入口通常在x86下是一个简单的4字节大小:

        Linux有对PTE中每个标志进程读取和设置的函数。标志位P高速处理器虚拟页面在物理内存中是否处于当前。如果清空(等于0),访问该页将触发一个缺页中断。要记住的是当该位为0时,其余的字段都无效。R/W位表示读/写;如果清空,该页为只读。标志位U/S表示用户/管理;如果清空,那么只有内核能够对他进行访问。这些标识用来实现内存的只读以及对内核空间进行保护,就像前面我们说的。

      标志位D和A是写脏位和访问控制位。一个脏页是已经被写过的页,而一个被访问的页是已经被写过或者读过的页。这两个标志位的相同点是:处理器只设置他们,而内核负责来清空他们。最后,PTE保存页面的起始物理地址,4KB对齐。这幼稚的前瞻域其实是痛苦的源泉,他限制了可寻址的物理内存为4GB。另一个PTE为的是另一件事情,即PAE。

       一个虚拟页面是内存保护的一个单元,因为他的所有字节共享U/S和R/W标志位。不管怎样,带有不用标志位、不同的页面可以映射相同的物理内存。注意在PTE中看不到他的执行权限。这就是经典x86分页允许在栈上执行代码的原因,这样很容易利用栈缓存溢出(当然,也可以利用不可执行栈使用返回到libc或其他技术)。缺少PTE的一个不可执行标志说明了一个广泛的事实:在VMA中的权限标志可能会也可能不会完全转化为硬件保护。内核做了他力所能及的,但是最终体系限制了这种可能。

       虚拟内存没有存储任何东西,他只是简单的映射一个程序的地址空间到相关的物理内存,这一大块物理内存叫做物理地址空间。然而在总线上的内存操作多少有些涉及,在这里我们可以忽略并假定物理地址范围从0到最大的可用内存以一个字节的形式增长。物理地址空间被内核分解成一个个页框。处理器不我知道也不关心页框,然而他们对内核来说很关键因为页框是物理内存管理器的单元。在32位模式下linux和windows都使用4KB大小的页框;这里有一个装有2GB RAM机器的例子:

       在linux中每个页框由一个描述符和几个标志描述。这些描述符一起跟踪计算机中物理内存入口;每个页框精确的状态总是指到的。物理内存由伙伴内存分配技术管理,如果一个页框能通过伙伴系统分配那么他是空闲的,也就是可分配的。一个分配的页框可能是匿名的,持有程序数据,他可能在页面缓存中,持有的数据存储在一个文件或者块设备中。当然页框还有其他用途,但是我们现在不考虑这些。Windows有一个类似的页框号(PFN)数据库来描述物理内存。

      让我们把虚拟内存区、页表入口和页框放在一起来说明这一切是怎么工作的。下面是一个用于堆的例子:

       蓝色矩形框代表在VMA区域中的页面,箭头代表页框中映射到页面的页表项。一些虚拟页面没有箭头;这意味着他们对应的PTE的Present标志位为0.这可能是这些页面没有被映射或者他们的内容已经被换出。在任何一种情况下访问这些页面都会导致缺页中断,尽管他们在VMA中。VMA和页表之间的这种关系可能看起来很奇怪,但是这是经常发生的。

       VMA就像是一个在你的程序和内核之间的契约。你要求一些事情被处理(内存分配、文件映射等等),内核说:“可以”,并且创建或者更新合适的VMA。但是他实际上并不履行请求权,他会等待指到一个缺页中断发生后才去做实际的工作。内核很懒,就是一个骗人的败类;这是虚拟内存的基本原则。这应用到大多数情形下,一些熟悉的一些令人吃惊的,但是规则是VMA记录达成了什么协议,而PTE反映内核实际做了什么。这两个数据结构一起管理一个程序的内存;包括解决缺页中断、释放内存、换出内存等等。让我们举一个内存分配的简单例子:

       当程序通过brk()系统调用申请更多的内存空间时,内核简单地更新堆的VMA。在这一点上,没有页框做实际的分配并且新分配的页面在内存中不是处于当前的。一旦程序进入这些页面,处理器缺页中断发生并且do_page_fault()被调用。他使用find_vma()函数搜索覆盖缺页中断虚拟地址空间的VMA。如果找到,VMA上的权限(读或者写)也会再次被检查。如果没有找到合适的VMA,没有契约覆盖试图进入的内存区,处理器产生段错误。

       当找到一个VMA,内核必须查看PTE内容和VMA的类型来处理这个缺页中断,在我们的例子中,PTE显示的页面不是当前的。实际上,我们的PTE是完全空白的(全是0),在linux中意味着虚拟页面没有被映射。一旦这是一个匿名VMA,我们必须由do_anonymous_page()来处理一个纯RAM事务,他分配一个页面帧,用它来映射发生缺页异常的虚拟页面。

       事情可能会有些不同。对一个换出页的PTE,例如,Present标志位为0但是整个不是0。他存储持有页面内容的交换位置,这个位置必须用do_swap_page()函数从磁盘上读取加载到一个页面,该函数被一个异常调用。

        这里总结了内核的用户内存管理器开始一半,在接下来的文章中,我们把文件加入进来,建立一个完整的内存基础构架图,包括他们实现的性能。

时间: 2024-12-28 07:27:37

内核怎样管理你的内存【转】的相关文章

十天学Linux内核之第三天---内存管理方式

原文:十天学Linux内核之第三天---内存管理方式 昨天分析的进程的代码让自己还在头昏目眩,脑子中这几天都是关于Linux内核的,对于自己出现的一些问题我会继续改正,希望和大家好好分享,共同进步.今天将会讲诉Linux如何追踪和管理用户空间进程的可用内存和内核的可用内存,还会讲到内核对内存分类的方式以及如何决定分配和释放内存,内存管理是应用程序通过软硬件协助来访问内存的一种方式,这里我们主要是介绍操作系统正常运行对内存的管理.插个话题,刚才和姐姐聊天,她快结婚了,说起了自己的初恋,可能是一句很

c语言内存空间-内存管理和动态分配内存

问题描述 内存管理和动态分配内存 请问ElemType p = NULL和ElemType *p = (ElemType)mallco(sizeof(ElemType))有区别吗? 解决方案 一个是在栈里面分配一个 elemtype 内存单元,数据为NULL,一个是在堆里面分配elemtype大小的内存单元,返回这段内存的头指针.在栈里面分配的,不用自己回收,在堆里面分配的必须自己回收. 解决方案二: 动态分配内存的原理动态分配内存之new动态分配内存与悬空指针 解决方案三: 我觉得有区别,第一

大话Linux内核中锁机制之内存屏障、读写自旋锁及顺序锁

大话Linux内核中锁机制之内存屏障.读写自旋锁及顺序锁     在上一篇博文中笔者讨论了关于原子操作和自旋锁的相关内容,本篇博文将继续锁机制的讨论,包括内存屏障.读写自旋锁以及顺序锁的相关内容.下面首先讨论内存屏障的相关内容. 三.内存屏障 不知读者是是否记得在笔者讨论自旋锁的禁止或使能的时候,提到过一个内存屏障函数.OK,接下来,笔者将讨论内存屏障的具体细节内容.我们首先来看下它的概念,Memory Barrier是指编译器和处理器对代码进行优化(对读写指令进行重新排序)后,导致对内存的写入

Windows任务管理器原理+内存管理机密+揭穿内存优化工具的骗局

我们在浏览网页时,也许会经常看到一些弹出广告,例如"整理内存碎片.提升系统性能".或者"大大减少系统和程序崩溃的可能性,回收垃圾内存"等等.如果点击这些弹出广告链接,则会看到某些所谓的优化软件,声称只需花费9.95.14.95或者29.95美元,就可以轻松实现所有的功能.看上去,这些工具软件确实不错,但是实际上最好的情况,这些所谓的内存优化工具没有任何效用:而最差的情况,则可能会严重降低系统性能. 盆盆评注 在国内,广告语更加精彩,"让您的系统运行如飞&q

linux-3.2.36内核启动2-setup_arch中的内存初始化1(arm平台 分析高端内存和初始化memblock)【转】

转自:http://blog.csdn.net/tommy_wxie/article/details/17093307 上一篇微博留下了这几个函数,现在我们来分析它们         sanity_check_meminfo();         arm_memblock_init(&meminfo, mdesc);         paging_init(mdesc);         request_standard_resources(mdesc);   在上一微博有展现根据启动参数初始化

深入解析PHP内存管理之谁动了我的内存_php技巧

首先让我们看一个问题: 如下代码的输出, 复制代码 代码如下: var_dump(memory_get_usage());$a = "laruence";var_dump(memory_get_usage());unset($a);var_dump(memory_get_usage());输出(在我的个人电脑上, 可能会因为系统,PHP版本,载入的扩展不同而不同):int(90440)int(90640)int(90472) 注意到 90472-90440=32, 于是就有了各种的结论

linux内存管理2:内存映射和需求分页(英文名字:demand Paging,又叫:缺页中断)【转】

转自:http://blog.csdn.net/zhangxinrun/article/details/5873148 当某个程序映象开始运行时,可执行映象必须装入进程的虚拟地址空间.如果该程序用到了任何一个共享库,则共享库也必须装入进程的虚拟地址空间.实际上,Linux 并不将映象装入物理内存,相反,可执行文件只是被链接到进程的虚拟地址空间中(磁盘空间中).随着程序的运行,被引用的程序部分会由操作系统装入物理内存.这种将映象链接到进程地址空间的方法称为"内存映射".可执行映像.每个进

使用KTM(内核事务管理器)进行文件事务处理

在本人最近的几篇关于事务处理的文章中,从事务处理的整体概念到具体的C#代码的实践操作基本上都已经能满足日常的开发需求.文章中大部分的事务范围类的操作都是局限于数据库,在本人的".NET简谈自定义事务资源管理器 "一文中我虽然实现了一个简单的自定义资源管理器,其实也能满足基本的项目需求,核心功能也实现了,但是对于文件事务操作我们是力不从心的.[王清培版权所有,转载请给出署名] 从数据库到自定义资源管理器都能参与到事务处理中来,在必要的时候保证数据的完整性,那么我们缺一个类型的资源操作,当

Linux内核剖析 之 内存管理

1. 内存管理区     为什么分成不同的内存管理区?     ISA总线的DMA处理器有严格的限制:只能对物理内存前16M寻址.     内核线性地址空间只有1G,CPU不能直接访问所有的物理内存.     ZONE_DMA                  小于16M内存页框     ZONE_NORMAL          16M~896M内存页框     ZONE_HIGHMEM        大于896M内存页框     ZONE_DMA和ZONE_NORMAL区域包含的页框,通过线性