linux内核中虚拟内存是怎样映射到物理内存16g虚拟内存

linux之虚拟内存相关介绍
互联网 & 04-15 17:14:22 & 作者:佚名 &
虚拟内存是个怎么强调也不过分的概念,它的存在极大地方便了程序设计任务,解放了程序员的手脚。下面看看虚拟内存的作用以及如何在存储管理机制的基础上实现它
什么是虚存?为什么需要它?   我们知道程序代码和数据必须驻留在内存中才能得以运行,然而系统内存数量很有限,往往不能容纳一个完整程序的所有代码和数据,更何况在多任务系统中,可能需要同时打开子处理程序,画图程序,浏览器等很多任务,想让内存驻留所有这些程序显然不太可能。因此首先能想到的就是将程序分割成小份,只让当前系统运行它所有需要的那部分留在内存,其它部分都留在硬盘。当系统处理完当前任务片段后,再从外存中调入下一个待运行的任务片段。的确,老式系统就是这样处理大任务的,而且这个工作是由程序员自行完成。但是随着程序语言越来越高级,程序员对系统体系的依赖程度降低了,很少有程序员能非常清楚的驾驭系统体系,因此放手让程序员负责将程序片段化和按需调入轻则降低效率,重则使得机器崩溃;再一个原因是随着程序越来越丰富,程序的行为几乎无法准确预测,程序员自己都很难判断下一步需要载入哪段程序。因此很难再靠预见性来静态分配固定大小的内存,然后再机械地轮换程序片进入内存执行。系统必须采取一种能按需分配而不需要程序员干预的新技术。   虚拟内存(之所以称为虚拟内存,是和系统中的逻辑内存和物理内存相对而言的,逻辑内存是站在进程角度看到的内存,因此是程序员关心的内容。而物理内存是站在处理器角度看到的内存,由操作系统负责管理。虚拟内存可以说是映射到这两种不同视角内存的一个技术手段。)技术就是一种由操作系统接管的按需动态内存分配的方法,它允许程序不知不觉中使用大于实际物理空间大小的存储空间(其实是将程序需要的存储空间以页的形式分散存储在物理内存和磁盘上),所以说虚拟内存彻底解放了程序员,从此程序员不用过分关心程序的大小和载入,可以自由编写程序了,繁琐的事情都交给操作系统去做吧。 实现虚拟内存   虚拟内存是将系统硬盘空间和系统实际内存联合在一起供进程使用,给进程提供了一个比内存大得多的虚拟空间。在程序运行时,只要把虚拟地址空间的一小部分映射到内存,其余都存储在硬盘上(也就是说程序虚拟空间就等于实际物理内存加部分硬盘空间)。当被访问的虚拟地址不在内存时,则说明该地址未被映射到内存,而是被存贮在硬盘中,因此需要的虚拟存储地址随即被调入到内存;同时当系统内存紧张时,也可以把当前不用的虚拟存储空间换出到硬盘,来腾出物理内存空间。系统如此周而复始地运转&&换入、换出,而用户几乎无法查觉,这都是拜虚拟内存机制所赐。   Linux的swap分区就是硬盘专门为虚拟存储空间预留的空间。经验大小应该是内存的两倍左右。有兴趣的话可以使用 swapon -s 查看交换分区大小。   大道理很好理解,无非是用内存和硬盘空间合成为虚拟内存空间。但是这一过程中反复运行的地址映射(虚拟地址映射到物理地址)和虚拟地址换入换出却值得仔细推敲。系统到底是怎么样把虚拟地址映射到物理地址上的呢?内存又如何能不断地和硬盘之间换入换出虚拟地址呢?   利用段机制能否回答上述问题呢?逻辑地址通过段机制后变为一个32位的地址,足以覆盖4G的内存空间,当程序需要的虚拟地址不在内存时,只依靠段机制很难进行虚拟空间地换入换出,因为不大方便把整段大小的虚拟空间在内存和硬盘之间调来调去(老式系统中,会笨拙地换出整段内存甚至整个进程,想想这样做会有那些恶果吧!)。所以很有必要寻找一个更小更灵活的存储表示单位,这样才方便虚拟地址在硬盘和内存之间调入调出。这个更小的存储管理单位便是页(4K大小)。管理页换入换出的机制被称为页机制。   因为使用页机制的原因,通过段机制转换得到的地址仅仅是作为一个中间地址&&线性地址,该地址不代表实际物理地址,而是代表整个进程的虚拟空间地址。在线性地址的基础上,页机制接着会处理线性地址映射:当需要的线性地址(虚拟空间地址)不在内存时,便以页为单位从磁盘中调入需要的虚拟内存;当内存不够时,又会以页为单位把内存中虚拟空间的换出到磁盘上。可见,利用页来管理内存和磁盘(虚拟内存)大大方便了内存管理的工作。毫无疑问,页机制和虚拟内存管理简直是&绝配&。 使用页机制,4G空间被分成2的20次方个4K大小的页面(页面也可定为4M大小),因此定位页面需要的索引表(页表)中每个索引项至少需要20位,但是在页表项中往往还需要附加一些页属性,所以页表项实际为32位,其中12位用来存放诸如&页是否存在于内存&或&页的权限&等信息。 前面我们提到了线性地址是32位。它其中高20位是对页表的索引,低12位则给出了页面中的偏移。线性地址经过页表找到页面基地址后和低12位偏移量相加就形成了最终需要的物理地址了。 在实际使用中,并非所有页表项都是被存放在一个大页表里,因为每个页表项占4个字节,如果要在一个表中存放2的20次方个页表项,就需要4M的连续存储空间。这么大的连续空间可不好找,因此往往会把页表分级存储,比如分两级,那么每级页表只需要4k连续空间了。   两级页表搜索如同看章回小说,先找到在哪一章里,然后在找在该章下的哪一节。具体过程看看下图: 综上所述,地址转换工作需要两种技术,一是段机制,二是页机制。段机制处理逻辑地址向线性地址的映射;页机制则负责把线性地址映射为物理地址。两级映射共同完成了从程序员看到的逻辑地址转换到处理器看到的物理地址这一艰巨任务。   你可以将这两种机制分别比作一个地址转换函数,段机制的变量是逻辑地址,函数值是线性地址;页机制的变量是线性地址,函数值是物理地址。地址转换过程如下所示。   逻辑地址&&(段函数)&&&线性地址&&(页函数)&&&物理地址。   虽然段机制和页机制都参与映射,但它们分工不同,而且相互独立互不干扰,彼此之间不必知道对方是否存在。   下面我们结合Linux实例简要地看看段页机制如何使用。 Linux中的分段策略   段机制在Linux里用得有限,并没有被完全利用。每个任务并未分别安排各自独立的数据段,代码段,而是仅仅最低限度的利用段机制来隔离用户数据和系统数据&&Linux只安排了四个范围一样的段,内核数据段,内核代码段,用户数据段,用户代码段,它们都覆盖0-4G的空间,所不同的是各段属性不同,内核段特权级为0,用户段特权级为3。这样分段,避免了逻辑地址到线性地址的转换步骤(逻辑地址就等于线性地址),但仍然保留了段的等级这层最基本保护。 每个用户进程都可以看到4G大小的线性空间,其中0-3G是用户空间,用户态进程可以直接访问;从3G-4G空间为内核空间,存放内核代码和数据,只有内核态进程能够直接访问,用户态进程不能直接访问,只能通过系统调用和中断进入内核空间,而这时就要进行的特权切换。 说到特权切换,就离不开任务门,陷阱门/中断门等概念。陷阱门和中断门是在发生陷阱和中断时,进入内核空间的通道。调用门是用户空间程序相互访问时所需要的通道,任务门比较特殊,它不含任何地址,而是服务于任务切换(但linux任务切换时并未真正采用它,它太麻烦了)。 对于各种门系统都会有对应的门描述符,和段描述符结构类似,门描述符也是由对应的门选择字索引,并且最终会产生一个指向特定段内偏移地址的指针。这个指针指向的就是将要进入的入口。利用门的目的就是保证入口可控,不至于进入到内核中不该访问的位置。 Linux中的分页策略   看看linux中如何使用分页。   Linux中每个进程都会有各自不同的页表,也就是说进程的映射函数互不相同,保证每个进程虚拟地址不会映射到相同的物理地址上。这是因为进程之间必须相互独立,各自的数据必须隔离,防止信息泄漏。   需要注意的是,内核作为必须保护的单独部分,它有自己独立的页表来映射内核空间(并非全部空间,仅仅是物理内存大小的空间),该页表(swapper_pg_dir)被静态分配,它只来映射内核空间(swapper_pg_dir只用到768项以后的项&&768个页目录可映射3G空间)。这个独立页表保证了内核虚拟空间独立于其他用户程序空间,也就是说其他进程通常状态下和内核是没有联系的(在编译内核的时候,内核代码被指定链接到3G以上空间),因而内核数据也就自然被保护起来了。   那么在用户进程需要访问内核空间时如何做呢?   Linux采用了个巧妙的方法:用户进程页表的前768项映射进程空间(&3G,因为LDT 中只指定基地址为0,范围只能到0xc0000000),如果进程要访问内核空间,如调用系统调用,则进程的页目录中768项后的表项将指向swapper_pg_dir的768项后的项,所以一旦用户陷入内核,就开始使用内核的页表swapper_pg_dir了,也就是说可以访问内核空间了。
大家感兴趣的内容
12345678910
最近更新的内容【图片】linux内存管理--虚拟内存管理理解【ubuntu驱动开发吧】_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0可签7级以上的吧50个
本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:22贴子:
linux内存管理--虚拟内存管理理解
一 为什么需要使用虚拟内存
大家都知道,进程需要使用的代码和数据都放在内存中,比放在外存中要快很多。问题是内存空间太小了,不能满足进程的需求,而且现在都是多进程,情况更加糟糕。所以提出了虚拟内存,使得每个进程用于3G的独立用户内存空间和共享的1G内核内存空间。(每个进程都有自己的页表,才使得3G用户空间的独立)这样进程运行的速度必然很快了。而且虚拟内存机制还解决了内存碎片和内存不连续的问题。为什么可以在有限的物理内存上达到这样的效果呢?二 虚拟内存的实现机制
首先呢,提一个概念,交换空间(swap space),这个大家应该不陌生,在重装系统的时候,会让你选择磁盘分区,就比如说一个硬盘分几个部分去管理。其中就会分一部分磁盘空间用作交换,叫做swap space。其实就是一段临时存储空间,内存不够用的时候就用它了,虽然它也在磁盘中,但省去了很多的查找时间啊。当发生进程切换的时候,内存与交换空间就要发生数据交换一满足需求。所以啊,进程的切换消耗是很大的,这也说明了为什么自旋锁比信号量效率高的原因。
那么我们的程序里申请的内存的时候,linux内核其实只分配一个虚拟内存( 线性地址),并没有分配实际的物理内存。只有当程序真正使用这块内存时,才会分配物理内存。这就叫做延迟分配和请页机制。释放内存时,先释放线性区对应的物理内存,然后释放线性区;&请页机制&将物理内存的分配延后了,这样是充分利用了程序的局部性原来,节约内存空间,提高系统吞吐;就是说一个函数可能只在物理内存中呆了一会,用完了就被清除出去了,虽然在虚拟地址空间还在。(不过虚拟地址空间不是事实上的存储,所以只能说这个函数占据了一段虚拟地址空间,当你访问这段地址时,就会产生缺页处理,从交换区把对应的代码搬到物理内存上来)三 物理内存与虚拟内存的布局左边是物理地址分配,与实际的CPU相关。4KB的这些都是一些控制器所占有,比如lcdc sd卡,他们的寄存器地址就是这样定死的。但是呢,我们要访问这些寄存器的时候,还是不能直接用,要使用内存管理的规则,使用虚拟地址去访问它,所以在驱动等内核程序中需要使用虚拟地址访问寄存器。如果有人直接使用物理地址访问寄存器,那么唯一的解释就是没有开mmu。不过这样你的进程就没有4G内存可以用了。物理地址分布:这是偷的别人的图啦,物理地址有896M直接映射到虚拟地址的内存空间,这是一一对应的映射,只有起始地址不一样,偏移是一样的。这个大小大多是固定的,哪怕你的内存超过一个G,太小了就另外说了。注意:用户区的代码也是放在这段物理地址里面的,就是说物理地址可以进行二次映射。但不管怎么样,这段物理地址都是受内核管理。当你内存很大的时候,超过896M时,剩余的那些内存怎么办呢?这多出来的叫做高端内存,如果你使用vmalloc申请空间,就会在高端内存中分配,如果你使用kmalloc申请空间,就会在小于896的内存中分配。所以还是很讲究的啊!!如果你的程序需要使用高端内存,就要调用内核API来分配,所以高端内存并不是想用就能用的哦。不过通过系统把一些应用常住在高端内存到是个好注意。不过前提是你的内存灰常大啊。为什么要这样做呢?先看看这里面放些什么?虚拟地址分布:关于0-3G用户空间内存的分布:谈到段式分布,就要说说逻辑地址,线性地址与物理地址的关系:linux通过段机制把逻辑地址转换为虚拟地址(就是线性地址),再通过页机制把虚拟地址转换为物理地址。所谓分段就是基址不同,偏移一样,比如说32位,一般程序里面都不会使用这么多的位,可以把前12位用作基址,后20位用作偏移,这样在特定段就可以只使用偏移寻址了。寻址很方便,不过linux页基址做的更好。最后呢再说几个点:1 线性地址空间:指linux系统中的虚拟地址空间。2 cpu寻址是属于物理地址。所以在使用cpu寻址前要把地址转换好。3 物理内存中的高端内存是DDR减去896M后多出来的那一段。虚拟地址里面的高端内存是指用于映射高端内存的虚拟地址空间。不过高端内存被映射到用户空间,那就是另外一回事了吧。4 内核空间是可以访问用户空间的,级别高就是好啊。不过不是通过虚拟地址直接访问的。
贴吧热议榜
使用签名档&&
保存至快速回贴新手园地& & & 硬件问题Linux系统管理Linux网络问题Linux环境编程Linux桌面系统国产LinuxBSD& & & BSD文档中心AIX& & & 新手入门& & & AIX文档中心& & & 资源下载& & & Power高级应用& & & IBM存储AS400Solaris& & & Solaris文档中心HP-UX& & & HP文档中心SCO UNIX& & & SCO文档中心互操作专区IRIXTru64 UNIXMac OS X门户网站运维集群和高可用服务器应用监控和防护虚拟化技术架构设计行业应用和管理服务器及硬件技术& & & 服务器资源下载云计算& & & 云计算文档中心& & & 云计算业界& & & 云计算资源下载存储备份& & & 存储文档中心& & & 存储业界& & & 存储资源下载& & & Symantec技术交流区安全技术网络技术& & & 网络技术文档中心C/C++& & & GUI编程& & & Functional编程内核源码& & & 内核问题移动开发& & & 移动开发技术资料ShellPerlJava& & & Java文档中心PHP& & & php文档中心Python& & & Python文档中心RubyCPU与编译器嵌入式开发驱动开发Web开发VoIP开发技术MySQL& & & MySQL文档中心SybaseOraclePostgreSQLDB2Informix数据仓库与数据挖掘NoSQL技术IT业界新闻与评论IT职业生涯& & & 猎头招聘IT图书与评论& & & CU技术图书大系& & & Linux书友会二手交易下载共享Linux文档专区IT培训与认证& & & 培训交流& & & 认证培训清茶斋投资理财运动地带快乐数码摄影& & & 摄影器材& & & 摄影比赛专区IT爱车族旅游天下站务交流版主会议室博客SNS站务交流区CU活动专区& & & Power活动专区& & & 拍卖交流区频道交流区
白手起家, 积分 199, 距离下一级还需 1 积分
论坛徽章:0
linux内核实现中进程的是不是也被分成了若干段,进程的每个段是如何映射到虚拟内存中的,如果想查找进程的代码段如何查找
用工具readelf
论坛徽章:22
用工具readelf-laptop:~/work/test$ readelf -S a.out
There are 29 section headers, starting at offset 0x1170:
Section Headers:
&&[Nr] Name& && && && &&&Type& && && && &Addr& &&&Off& & Size& &ES Flg Lk Inf Al
&&[ 0]& && && && && && & NULL& && && && &000 & && &0& &0&&0
&&[ 1] .interp& && && &&&PROGBITS& && &&&134 & &A&&0& &0&&1
&&[ 2] .note.ABI-tag& &&&NOTE& && && && &148 & &A&&0& &0&&4
&&[ 3] .note.gnu.build-i NOTE& && && && &168 & &A&&0& &0&&4
&&[ 4] .gnu.hash& && && &GNU_HASH& && &&&018c & &A&&5& &0&&4
&&[ 5] .dynsym& && && &&&DYNSYM& && && & 080481ac 0001ac & &A&&6& &1&&4
&&[ 6] .dynstr& && && &&&STRTAB& && && & 080481fc 0001fc 00004c 00& &A&&0& &0&&1
&&[ 7] .gnu.version& && &VERSYM& && && & 248 00000a 02& &A&&5& &0&&2
&&[ 8] .gnu.version_r& & VERNEED& && && &254 & &A&&6& &1&&4
&&[ 9] .rel.dyn& && && & REL& && && && & 274 & &A&&5& &0&&4
&&[10] .rel.plt& && && & REL& && && && & 027c & &A&&5&&12&&4
&&[11] .init& && && && & PROGBITS& && &&&294 &&AX&&0& &0&&4
&&[12] .plt& && && && &&&PROGBITS& && &&& 040 04&&AX&&0& &0&&4
&&[13] .text& && && && & PROGBITS& && &&&310 0001cc 00&&AX&&0& &0 16
&&[14] .fini& && && && & PROGBITS& && &&&080484dc 0004dc 00001c 00&&AX&&0& &0&&4
&&[15] .rodata& && && &&&PROGBITS& && &&& 016 00& &A&&0& &0&&4
&&[16] .eh_frame& && && &PROGBITS& && &&&510 & &A&&0& &0&&4
&&[17] .ctors& && && && &PROGBITS& && &&&f14 &&WA&&0& &0&&4
&&[18] .dtors& && && && &PROGBITS& && &&&0f1c &&WA&&0& &0&&4
&&[19] .jcr& && && && &&&PROGBITS& && &&&f24 &&WA&&0& &0&&4
&&[20] .dynamic& && && & DYNAMIC& && && &f28 &&WA&&6& &0&&4
&&[21] .got& && && && &&&PROGBITS& && &&&0ff0 &&WA&&0& &0&&4
&&[22] .got.plt& && && & PROGBITS& && &&&0ff4 &&WA&&0& &0&&4
&&[23] .data& && && && & PROGBITS& && &&&100c &&WA&&0& &0&&4
&&[24] .bss& && && && &&&NOBITS& && && & 014 &&WA&&0& &0&&4
&&[25] .comment& && && & PROGBITS& && &&&014 00006c 01&&MS&&0& &0&&1
&&[26] .shstrtab& && && &STRTAB& && && & 080 0000ee 00& && &0& &0&&1
&&[27] .symtab& && && &&&SYMTAB& && && & 5f8 & &&&28&&44&&4
&&[28] .strtab& && && &&&STRTAB& && && & 9f8 & && &0& &0&&1
Key to Flags:
&&W (write), A (alloc), X (execute), M (merge), S (strings)
&&I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
&&O (extra OS processing required) o (OS specific), p (processor specific)复制代码
白手起家, 积分 199, 距离下一级还需 1 积分
论坛徽章:0
123.png (111.5 KB, 下载次数: 11)
23:52 上传
丰衣足食, 积分 625, 距离下一级还需 375 积分
论坛徽章:0
cat /proc/pid/maps
白手起家, 积分 71, 距离下一级还需 129 积分
论坛徽章:0
我的理解:
elf为例,典型情况下是这样的,shell执行新的命令/程序时,他会fork出一个子进程,子进程复制父进程的所有资源(写时复制),然后execve()。execve根据elf映像文件中的程序头给出的映射关系把磁盘上的elf映像映射到虚拟内存中,同时修改mm结构中的线性区vma等数据结构。这样, 完成了磁盘文件到虚拟内存的映射。注意,磁盘elf文件并没有调入/拷贝到物理内存,也没有建立真正的页表,只有当进程正真执行时通过缺页异常来完成程序加载,同时建立页表。这样就完成了虚拟内存到物理内存的映射。
等高手拍砖。。。
白手起家, 积分 199, 距离下一级还需 1 积分
论坛徽章:0
up up 顶一下。。。
白手起家, 积分 199, 距离下一级还需 1 积分
论坛徽章:0
amarant 发表于
用工具readelf
这个看不明白,是象我说的那样的内存映射么?
论坛徽章:22
& & 代码段是.text
.text& && && && & PROGBITS& && &&&310 0001cc 00&&AX&&0& &0 16
这句的意思就是1,代码段从虚拟地址开始;2,长度为1cc;3在二进制文件的310地址开始
富足长乐, 积分 5503, 距离下一级还需 2497 积分
论坛徽章:2
你这个图。。。 所有进程共用同一个平面的虚拟地址空间。。。。好像Linux 0.01里是这么做的。
稍有积蓄, 积分 426, 距离下一级还需 74 积分
论坛徽章:0
你的图的确是很久以前的做法,
北京盛拓优讯信息技术有限公司. 版权所有 京ICP备号 北京市公安局海淀分局网监中心备案编号:22
广播电视节目制作经营许可证(京) 字第1234号
中国互联网协会会员&&联系我们:
感谢所有关心和支持过ChinaUnix的朋友们
转载本站内容请注明原作者名及出处Linux内核空间和用户空间_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
Linux内核空间和用户空间
阅读已结束,下载本文需要
想免费下载更多文档?
定制HR最喜欢的简历
下载文档到电脑,同时保存到云知识,更方便管理
还剩10页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢}

我要回帖

更多关于 物理内存与虚拟内存 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信