linux:谁能给我解释下虚拟地址和物理地址的联系?

作者&投稿:司马仇 (若有异议请与网页底部的电邮联系)
Linux下怎样在进程中获取虚拟地址对应的物理地址~

Linux文件目录中的/proc记录着当前进程的信息,称其为虚拟文件系统。在/proc下有一个链接目录名为self,这意味着哪一个进程打开了它,self中存储的信息就是所链接进程的。self中有一个名为page_map的文件,专门用来记录所链接进程的物理页号信息。这样通过/proc/pid/page_map文件,允许一个用户态的进程查看到每个虚拟页映射到的物理页
/proc/pid/page_map中的每一项都包含了一个64位的值,这个值内容如下所示。每一项的映射方式不同于真正的虚拟地址映射,其文件中遵循独立的对应关系,即虚拟地址相对于0x0经过的页面数是对应项在文件中的偏移量
* /proc/pid/pagemap. This file lets a userspace process find out whichphysical frame each virtual page is mapped to. It contains one 64-bitvalue for each virtual page, containing the following data (fromfs/proc/task_mmu.c, above pagemap_read):* Bits 0-54 page frame number (PFN) if present//present为1时,bit0-54表示物理页号* Bits 0-4 swap type if swapped* Bits 5-54 swap offset if swapped* Bit 55 pte is soft-dirty (see Documentation/vm/soft-dirty.txt)* Bit 56 page exclusively mapped (since 4.2)* Bits 57-60 zero* Bit 61 page is file-page or shared-anon (since 3.5)* Bit 62 page swapped* Bit 63 page present//如果为1,表示当前物理页在内存中;为0,表示当前物理页不在内存中
在计算物理地址时,只需要找到虚拟地址的对应项,再通过对应项中的bit63判断此物理页是否在内存中,若在内存中则对应项中的物理页号加上偏移地址,就能得到物理地址
通过程序获取物理地址并验证写时拷贝技术
#include #include #include #include #include #include #include //计算虚拟地址对应的地址,传入虚拟地址vaddr,通过paddr传出物理地址void mem_addr(unsigned long vaddr, unsigned long *paddr){int pageSize = getpagesize();//调用此函数获取系统设定的页面大小unsigned long v_pageIndex = vaddr / pageSize;//计算此虚拟地址相对于0x0的经过的页面数unsigned long v_offset = v_pageIndex * sizeof(uint64_t);//计算在/proc/pid/page_map文件中的偏移量unsigned long page_offset = vaddr % pageSize;//计算虚拟地址在页面中的偏移量uint64_t item = 0;//存储对应项的值int fd = open("/proc/self/pagemap", O_RDONLY);。。以只读方式打开/proc/pid/page_mapif(fd == -1)//判断是否打开失败{printf("open /proc/self/pagemap error
");return;}if(lseek(fd, v_offset, SEEK_SET) == -1)//将游标移动到相应位置,即对应项的起始地址且判断是否移动失败{printf("sleek error
");return;}if(read(fd, &item, sizeof(uint64_t)) != sizeof(uint64_t))//读取对应项的值,并存入item中,且判断读取数据位数是否正确{printf("read item error
");return;}if((((uint64_t)1 << 63) & item) == 0)//判断present是否为0{printf("page present is 0
");return ;}uint64_t phy_pageIndex = (((uint64_t)1 << 55) - 1) & item;//计算物理页号,即取item的bit0-54*paddr = (phy_pageIndex * pageSize) + page_offset;//再加上页内偏移量就得到了物理地址}const int a = 100;//全局常量int main(){int b = 100;//局部变量static c = 100;//局部静态变量const int d = 100;//局部常量char *str = "Hello World!";unsigned long phy = 0;//物理地址char *p = (char*)malloc(100);//动态内存int pid = fork();//创建子进程if(pid == 0){//p[0] = '1';//子进程中修改动态内存mem_addr((unsigned long)&a, &phy);printf("pid = %d, virtual addr = %x , physical addr = %x
", getpid(), &a, phy);}else{mem_addr((unsigned long)&a, &phy);printf("pid = %d, virtual addr = %x , physical addr = %x
", getpid(), &a, phy);}sleep(100);free(p);waitpid();return 0;}
测试结果如下:
全局常量:符合写时拷贝技术
局部变量:不符合写时拷贝技术。原因分析,有可能是物理页上的其他数据被改动,导致拷贝出一个新物理页面
局部静态变量:不符合写时拷贝技术。原因分析,有可能是物理页上的其他数据被改动,导致拷贝出一个新物理页面
局部常量:不符合写时拷贝技术。原因分析,有可能是物理页上的其他数据被改动,导致拷贝出一个新物理页面
字符串:符合写时拷贝技术
动态内存:符合写时拷贝技术 子进程不修改动态内存 子进程修改动态内存
*其实想要知道虚拟地址对应的物理地址,通过这样的方式也可以得到物理地址而不用操作MMU。。。*

以上就是Linux下怎样在进程中获取虚拟地址对应的物理地址的全文介绍,希望对您学习和使用linux系统开发有所帮助.

不是仅仅 Linux 是这么设计的,整个现代流行的操作系统都是这么设计的。
应用程序被读入内存后,为了保证系统的统一性,所有的程序都有同样的一套寻址规范。这个寻址就是虚拟地址。这个虚拟地址是系统提供转换的,不是程序的工作。


如果系统不提供这个功能,那么应用程序就需要自己去寻找没有被使用的内存,以及还要自己去处理内存容量的问题,而且如果程序调用外部的一些函数库,这些函数库也需要分配内存,这会导致应用程序的设计难度非常大,每个应用程序实际上就是一个操作系统了。多个程序共同运行导致内存使用混乱也很容易出现。
应用程序申请内存,使用的是操作系统的内存分配功能。这样操作系统可以根据实际情况给应用程序内存,程序不需要考虑因为内存位置不同而必须不同编写的难度。而且操作系统还可以提供虚拟内存等等各种方式来扩充内存,这样的内存对于应用程序来说是不需要考虑的,一切都有系统打理。


使用虚拟地址后,对于应用程序来说,他的内存使用不需要考虑其他的程序占用,也不需要考虑内存容量的问题,也不需要考虑内存块位置,函数库的调用也都扔给操作系统打理。这使得应用程序不需要考虑具体如何管理内存,只需要考虑作为应用程序的应用部分。

而且,因为内存是虚拟的,应用程序一些函数调用,操作系统可以把多个应用程序的调用都用同一套数据来处理,这样,既可以节约内存使用(就是启动100个应用程序,也只需要内存里有一套函数库而已),也可以做到外部函数库和应用程序没有直接关联,纯粹是由系统做虚拟地址过渡。


至于为什么 4G ,这是传统+一些兼容的考虑。
以前没有这个技术时,每个程序都可以完全使用整个系统,整个空间是连续的。到了这种虚拟地址的方式后,每个程序还是有自己“独立”的一整套内存地址。但每个程序内存使用量肯定不一样。那么多少内存空间才完全够用呢?当时因为正好使用了 32 位系统。那么就把整个 32 位环境支持的 4G 内存容量作为这个极限。
不过因为内存地址是虚拟的。实际应用程序要用内存,是需要先申请的,所以只有程序申请后,真实内存才会被占用。这个 4G 只是在算法上作为极限。

不过因为 4G 也是硬件极限。所以 4G 以外的地址都是不能使用的,这就导致另一个问题,一些硬件有存储器,有些硬件需要存储空间做交互(比如 PCI ,比如各种硬件,比如 AGP 显卡)。这些存储区域怎么处理?
所以,Windows Vista 的 32 位版在 4G 内存的机器上曾经报出只有 3.5G (有的机器甚至只有 3.25G 可以用)。就是这个问题的解决办法导致的:把硬件的内存用虚拟地址的方式,放到虚拟地址的最后面。这样应用程序调用硬件存储时,可以直接按照内存的方式读写。这样应用程序就很好的统一了存储界面:只有 4G 的内存范围,不存在其他方式的存储调用方式(硬盘需要用读写功能读取到内存后才能处理,而不是直接进行处理)。这样应用程序的开发就很简单,而且整个内存的使用每个程序都一样。不存在各种硬件的原因而不同导致的需要重新设计内存管理算法。操作系统也能根据实际应用程序的需要随时分配数据,也可以根据每个程序的运行情况,区别的提供物理内存或者虚拟的内存。

这么设计最大的一个好处是,硬件环境和应用程序是无关的,中间由操作系统做转换。而且应用程序互相之间也没有影响,就好象整个内存都由他自己一个程序使用一样。

PS:说了半天,我发现我自己也说不清楚其中的缘由……

这个问题很大。。。。我尽自己所能给你解释一下吧,如果你不能完全看懂,以后可以回头再翻翻来看。关于虚拟内存的事情,大概是这样的:
首先你要明确什么是虚拟内存。虚拟内存实际上是操作系统对于内存管理的一种方式,比如说,对每个程序而言,它的内存编址都从0x00到0xff,但是实际上,这些内存对应的物理地址,应用程序本身是无法知道的,在这里就可以理解成操作系统对内存管理的一层抽象。
比如,可能进程init的虚拟地址0x00对应了物理地址的0x10,而kthreadd的虚拟地址0x00对应物理地址0x20,etc.
而且虚拟内存也是一种有效的进程间隔离的方式,极大的提升了进程的安全性和操作系统的稳定性,也就是我一个进程不管做什么,都是在它自己的地址空间里做的,不会影响到其他进程和OS。
当然这是理想情况,实际上还有进程间通信啦之类,这就不在这个问题的范围之内了。
而具体怎么把这些虚拟地址对应到物理地址上,这是操作系统做的事情,估计这个也就是你的问题。
----以上是背景1-----
然后我要明确一下:地址总线4位的意思是说内存用4个bit位来表达地址,所以能够index的地址位就是2^0-2^4,也就是0x0到0xf,就是16个bit的内存空间。
然后我们再来细化一下你的例子,就比方说在你的16bit的内存的机器上有1个OS,上面跑着2个程序。一般来说OS会保留地址的高位,比如11-15bit的位置,作为kernel space;然后0-10bit是user space。
在以上的前提下,虚拟内存的效果是:在每一个程序看来,这个程序都有0x0到0xf的地址可以用,并且它们的0xb-0xf都是shared kernel space,然后0x0-0xa都是自己的user space,这样仿佛就有了32个bit的地址一样。这就是你所谓的是用虚拟地址可以使总的地址操作物理地址。至于os是怎么做到这点的,继续往下看。
-----以上是背景2-----
操作系统对每一个进程有一个进程控制块,叫PCB,Process Control Block,里边存储了每一个进程的进程信息,比如说寄存器,file descriptor,还有我们最关心的内存映射信息。每一个进程有一个递增的id号,叫pid,也就是Process IDentifier.
-----以上是背景3-----
进程间切换,也就是说,比如说你一个系统只有1个CPU,但是有两个进程要跑,而且要让我们看起来好像是两个进程同时在跑一样。为什么我要提到这个呢,后面继续看。
-----以上是背景4-----
好,现在来讲如何把虚拟地址映射到物理地址。从程序的角度来看,从malloc开始讲起,比如,在某一时刻,一个进程调用了malloc,在堆(heap)上申请了2bits的空间。实际上这个行为的流程是,程序调用malloc,进入内核模式之后,调用mmap,如果成功,操作系统会从物理地址上取一块2bits的内存,交给应用程序编入虚拟地址空间。更详细一点说,每个进程对内存管理是一个红黑树的结构,也就是说,在每一个进程的PCB,里维护了一颗红黑树,然后动态的将所有的新分配的内存加到这个红黑树里边,以保证程序对每一块内存的访问时间是差不多的。然后不知道你们教材中有没有提到页表(page table),页表也是PCB中的一项,你们教材中应该会对页表有详细的讲解,将如何对内存的地址进行换算,之类的。然后你要明确,页表实际上是红黑树的cache,这样可以加速程序对于常用的内存的访问速度。
以上是操作系统对内存管理的一个大致概括,就是一块物理的内存如何映射成为一块虚拟的内存。
我在背景2中说,两个程序都看到自己有16个bit的虚拟地址,总共有32bit,但是实际上硬件只有16bits,也就是说,不管你在红黑树和页表中怎么映射,一定会有冲突发生,比如,可能物理地址的0x02对应了进程1中的0x04,又在进程2的PCB中映射到了pid2的虚拟地址位0x06上。操作系统如何解决这个矛盾呢,首先在进程pid 1运行的时候,这个0x02对应的是pid1中的0x04;然后这个时候进程切换发生了,pid 2开始运行。当pid2需要用到它的0x04时,os发现0x02这个地址在pid1中也有映射,于是它就把0x02这个地址上的内容存到硬盘上的一个叫swap的空间内,然后把这个地址交给pid2使用。这样就达到了扩大虚拟地址的效果。
但是这样做是有代价的,因为一旦这个page被swap出去,那么在pid1再来调用的时候会发生一系列的miss,从L1 cache miss到 L2 cache miss到L3 cache miss,然后页表miss,memory miss,会对程序的性能造成极大的影响。影响有多大呢,平均来说:
L1 cache hit: 0.5ns
L2 cache hit: 7ns
主内存引用:100ns
顺序从内存中读取1MB:250,000ns
硬盘寻道:10,000,000ns
从硬盘上顺序读取1MB:30,000,000ns
所以你就可以知道这种行为是以极大的性能为代价的。
----讲完啦-----
总的来说这个很大的话题,我刚才所写的东西的就是试图让你对虚拟内存这个东西有一个基本的概念,然后大致的了解内存是如何映射的。就我现在能想到的,对这个虚拟内存话题的讨论还包括多级页表,进程间隔离&通信以及memory fragment。
个人水平有限,如果以上有什么地方说错的或者遗漏的,还请各位多多补充和批评,谢谢。

虚拟就是虚拟的,不是实际真是的物理地址。你可以认为,这两个地址之间没关系。
这个虚拟是通过系统和硬件的双重工作,做的一种点对点的映射(当然实际内存分配是按照页来处理)。
也就是软件不需要考虑内存数据的物理地址,只需要用虚拟地址做数据存储处理就行了。

这样一个好处是,软件不需要自己做内存分配,也不需要考虑别的软件的内存占用问题。操作系统会根据当前的内存使用情况,动态的分配内存空间。虚拟内存地址还一个好处是因为是虚拟的,所以内存并不一定非要在物理内存中。可以存放在任何位置,比如把暂时不用的数据放进硬盘上的虚拟内存,腾出真实的物理内存交给程序运行而提高多程序时运行的效率。而且因为每个软件的虚拟内存地址都是从 0 开始,每个软件的寻址都是独立而且顺序的。程序编写和运行时,都好像是机器里面只有自己一个程序在运行,程序开发起来也很容易。软件不需要考虑内存分配的问题,也不需要担心内存不足和两个程序抢同一片内存导致系统整个崩溃的情况。


有谁能帮我做一下几道Linux命令的题。
使用ping命令: ping -c 8 -i 10 198.10.23.334 ip可以替换为你要查看的页面 楼上的while语句是不正确的,因为默认ping会一直进行下去,不会停 4、确定你当前的目录并显示当前工作目录的内容 应该使用 pwd && ls 5、在主目录下以自己的学号创建一子目录,将工作目录改变到子目录,将当前日期...

谁能给我推荐一套稳定,支持多用户、Linux平台的邮件服务器
最新想把服务器换成Linux,原来的imail服务器没有Linux的版本,谁能给我推荐一个跟imail一样强在的邮件服务器谢谢... 最新想把服务器换成Linux,原来的imail服务器没有Linux的版本,谁能给我推荐一个跟imail一样强在的邮件服务器谢谢 展开  我来答 1...

哪里有Linux的内核源代码?给我个地址谢谢
还有使用Linux为的是来开发无线连接产品的开发者越来越多。Linux在快速增长的无线连接应用主场中有一个非常重要的优势,就是有足够快的开发速度。这是因为LInux有很多工具,并且Linux为众多程序员所熟悉。因此,我们要在嵌入式系统中使用Linux操作系统。 Linux的大小适合嵌入式操作系统——Linux固有的模块性,...

谁能给我提供一个Xandros Linux系统的下载地址?
这个是下载地址:http:\/\/www.xp510.com\/soft\/Linux\/366\/1.html 这个也可以看看,了解:http:\/\/www.linux521.com\/

关于linux系统 本人新手小白一个 什么都不懂 应该如何着手 希望能够...
等你装上了linux,你才刚刚跨进linux的大门,以后学习如何使用它(无论是你要拿linux干嘛,你都必须花时间把系统的日常操作和管理学习一下),并让它完全服从于你,这个就靠楼主自己了。我个人觉得楼主的问题很奇怪,在你学习如何安装linux的时候,你就开始学习linux的基础了,等你能将一个linux系统熟练...

想从事嵌入式linux方面的工作,请问各位大侠们谁能告诉我应该做什么应...
后来我又找到一份很好的视频,是在嵌入式学习网推出的一份视频《嵌入式视频教程--零基础手把手教你学嵌入式》,里面的教程还不错,很完整,可以让我从基础的开始学起。视频不便宜啊,但是我也忍了,毕竟买几本书都要几百了,何况他们还有半年的技术咨询和服务,算值了。===这里我就不给出他们的网...

在linux中 \/boot \/ \/home \/swap 是什么意思啊,还有其他的目录,谁能和...
给你几个常用的把 跟目录\/,这个是linux系统所有东西都在这里 \/boot用来引导系统的,\/home是用户目录,相当于windows的“我的文档”没有\/swap只有swap,swap是个磁盘格式,用来做虚拟内存的。另外其他的,例如\/usr是linux程序默认安装目录。\/tmp是存放系统临时文件缓存的,系统会自动清理里面的东西。lz...

哪位高手给我一个linux下jdk1.4.2 64位的安装?急!谢谢
下面是官方下载地址:http:\/\/java.sun.com\/javase\/downloads\/jdk\/142\/ JDK 1.4.2_19 X86的平台直接用 Linux版本就能跑.

我是一个linux的新手 不知道该学习哪些最基本的命令,谁能帮帮啊???
不知道你是怎么装Linux的,建议你下载VirtualBox虚拟机来安装Ubuntu,Fedora,CentOS,Linuxmint,openSUSE这些Linux发行版本中的一个来不断的练习,现在Linux的发行版本又出现了一个过渡时期(gnome向平板的过渡),建议你下载最新的进行学习,如果是想向服务器方面发展,就学CentOS或其它的一些老的版本。以下...

linux磁盘配额的一个题,谁帮我解决下
根据你所说的,就是对根分区进行磁盘配额。(以RHEL5为例,也只有根分区与交换分区)步聚如下:1、首先修改“\/etc\/fstab”文件,在第一行的defaults后面加上usrquota,grpquota字段,然后退出保存。具体如图所示:2、重新挂载文件系统,或者重启:reboot 3、用quotacheck -cmug命令创建配额文件。根据你说...

比如县15365642275: linux 虚拟地址,到底怎么理解 -
检黄联磺: linux的虚拟地址分为物理地址和虚拟地址 . Linux系统中的物理存储空间和虚拟存储空间的地址范围分别都是从0x00000000到0xFFFFFFFF,共4GB. 1、物理地址 Linux的物理存储空间布局与处理器相关,详细情况可以从处理器用户手册的存...

比如县15365642275: linux:谁能给我解释下虚拟地址和物理地址的联系? -
检黄联磺: 这个问题很大....我尽自己所能给你解释一下吧,如果你不能完全看懂,以后可以回头再翻翻来看.关于虚拟内存的事情,大概是这样的: 首先你要明确什么是虚拟内存.虚拟内存实际上是操作系统对于内存管理的一种方式,比如说,对每...

比如县15365642275: linux操作系统 虚拟地址问题 在学习操作系统时,经常会说程序员编写程序使用的是虚拟地址空间,我 -
检黄联磺: 这个地址你%p 就能打印出来了 比如说系统有4G的空间,有1G是给内核的,3G是给用户的,这3G里面就包括静态全局区、栈、堆、代码区等 系统在运行一个程序时,会先将硬盘的程序上传到内存的代码段然后执行,在遇到局部变量时,系统会在栈里为它开辟一块空间存储数据,遇到全局或静态变量就会在静态全局区开辟一块空间用来存储数据,这些都是系统为我们自动分配的地址,而用户也可以自己分配地址存储数据 例如: int *p = (int *)0; *p = 123;这样我们就将整形数据123存储在0地址上了 你说的程序对应的虚拟地址,你将程序反汇编,我记得那里面就有每一条指令的地址,主函数入口的地址就是你程序对应的虚拟地址

比如县15365642275: 请问下虚拟地址的问题 -
检黄联磺: 那个账号提交有问题,换个账号回答你.首先,虚拟地址和逻辑地址是一样的概念.linux分段的时候把不同进程映射到不同的线性地址,是在linux 0.11内核代码中出现的.之所以这样是因为,0.11版本虽然开启了分页机制,但是所有进程共享了同一个页目录,所以进程们只能分配其中一段使用.这时候每个进程的线性地址空间没有那么大(没有4GB).后来linux内核为了增大单个进程的线性地址空间,就不再共享页目录,也就是每个进程有独立的页目录,此时进程的段地址基址就可以设置为0,而不会再相互干涉.每个进程基址都从0开始,并且都拥有4GB的线性地址空间,这就相当于没有使用分段机制,实际上分段和分页都采用了.

比如县15365642275: 虚拟地址的相关比较 -
检黄联磺: 下面我们看看什么是物理地址,什么是虚拟地址.物理地址 (physical address): 放在寻址总线上的地址.放在寻址总线上,如果是读,电路根据这个地址每位的值就将相应地址的物理内存中的数据放到数据总线中传输.如果是写,电路根据...

比如县15365642275: Linux 内核从哪个阶段开始使用虚拟地址的? -
检黄联磺: 一般是在kernel/head_32.S文件,early_init之后,会调用relocate_kernel,重定向,KERNELBASE为内核的虚拟起始地址,接着trun_on_mmu中,跳转到start_here,然后就是虚拟地址了.

比如县15365642275: Linux虚拟地址,地址映射表,物理内存与虚拟内存的关系 -
检黄联磺: 内存是一种存储设备,现在一般是DDR SDRAM,地址是用来标记内存的数据的.在操作系统中物理内存指实际的DDR SDRAM,而虚拟内存指的是在硬盘中的缓存,windows中是页面文件,linux中是swap分区.cpu产生的地址是虚拟地址也可以称作有效地址,而在cpu外地址线上的信号称作实际地址或物理地址.这2类地址有某种对应关系,由操作系统管理.如果是x86架构的话,物理地址和虚拟地址中间还有线性地址的概念.

比如县15365642275: Linux进程虚拟地址空间的分布,以及堆和栈的区别 -
检黄联磺: 一、具体分布如图所示:二、关于堆和栈 (1)分配方式: 栈:由编译器自动分配释放,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. 堆: 一般由程序员分配释放,它的分配方式类似于链表. (2)申请后系统的响...

比如县15365642275: linux中虚拟地址和物理地址怎样映射 -
检黄联磺: /**伪代码,示例*32位地址,三级映射(没有pud_t),页面大小4KB*/ unsigned long addr = 0x12345678;//要找的虚拟地址,用户空间所访问的地址 unsigned long real_addr = 0x00;//要输出的地址 struct task_struct *cur_task = get_current()...

比如县15365642275: linux虚拟地址怎么映射物理地址 -
检黄联磺: 每个进程都是独立的虚拟地址空间,两个独立进程的相同地址互不干扰,但是在物理上对每个进程可能也就分了一部分空间给了某个进程,所以中间就要用到映射,调度某个进程执行时,就要把它的地址空间映射到一个物理空间上

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网