【进程地址空间=虚拟地址空间=C/C++程序地址空间就是那个4G的空间】
虚拟内存是操作系统内核为了对进程地址空间进行管理,而设计的一个逻辑意义上的内存空间概念。在程序运行过程中,虚拟内存中需要被访问的部分会被映射到物理内存空间中,CPU 通过将虚拟地址翻译成物理地址,这样才能访问到真实的物理内存,使得程序顺利执行。
【比如我们在写完一段C++程序之后都需要采用g++进行编译,这时候编译器采用的地址其实就是虚拟内存空间的地址。因为这时候程序还没有运行,指令和数据还没有被加载到内存中,那此时使用的就是虚拟内存的地址了。】
运行进程时,通过页表将虚拟内存内容与真实物理空间内容对应。内核会为系统中每个进程维护一个页映射表。页映射表的基本原理是将程序运行过程中需要访问的段虚拟内存空间通过页映射表映射到一段物理内存空间上,这样CPU访问对应虚拟内存地址的时候就可以通过这种查找页映射表的机制访问物理内存上的某个对应的地址。
虚拟内存的最大容量是由计算机的地址结构(CPU寻址范围)确定的。
虚拟内存的实际容量 = min(内存和磁盘容量之和,CPU寻址范围)。
比如:
某计算机地址结构 32 位,内存大小为 512M,磁盘大小为 2GB,则:
虚拟内存的最大容量 = 2^32B = 4GB。
虚拟内存的实际容量 = min(2^32B, 512MB+2GB) = 2GB+512MB。
无论命中与否,都会访问两次内存。
若访问页表发现页命中(即,页被加载到物理内存):
首先CPU(CPU调用MMU)根据虚拟地址访问内存中的页表,获取到页表的中描述的所需数据存放在物理内存位置,再次访问内存,获得真正的数据。
若访问页表发现未页命中(即,页未被加载到物理内存):
首先CPU(CPU调用MMU)根据虚拟地址访问内存中的页表,获取到页表后发现发现页不在内存中,未命中,因此MMU发送一个缺页中断,交由缺页异常处理程序处理。缺页异常处理程序根据页置换算法,选择出一个牺牲页,如果这个页面已经被修改了,则写出到磁盘上。并将这个牺牲页的页表项有效位设置为0,存入磁盘地址。对于新调入的页面,如果该虚拟页尚未分配磁盘空间,则分配磁盘空间,然后磁盘空间的页数据拷贝到该物理页上,并更新有效位为1,更新对应的物理页号。完成这些操作后,从缺页异常处理程序返回,重新按照页表项命中的步骤执行。
————————————————
原文链接:https://blog.csdn.net/daocaokafei/article/details/116207148
现代处理器使用的是一种称为 虚拟寻址(Virtual Addressing) 的寻址方式。使用虚拟寻址,CPU 需要将虚拟地址翻译成物理地址,这样才能访问到真实的物理内存。 实际上完成虚拟地址转换为物理地址转换的硬件是 CPU 中含有一个被称为 内存管理单元(Memory Management Unit, MMU) 的硬件
“页(page)"是虚拟内存空间向物理内存空间映射的基本单元.
我们程序中各个变量等使用的地址其实都是这个虚拟内存空间中的地址。在编程过程中我们面对的也都是逻辑地址。
【可省略】举个最简单的例子,父子进程各种有一份虚拟空间地址,在子进程刚被创建时,父子进程代码和数据共享,所以此时虚拟地址空间的内容是基本一样的(当然有部分数据不同,比如各子的id等),且映射关系也是一样的,但是当子进程对数据进行修改时,子进程对那份数据进行写时拷贝,所以物理空间地址发生了变化,但是虚拟地址还是没有发生变化,只是改变了子进程的页表中那份虚拟地址的映射关系而已,所以两个相同的虚拟地址在父子进程分别看到了不同的物理地址空间。
————————————————
原文链接:https://blog.csdn.net/weixin_58450087/article/details/123461959
比方说你的进程申请了一个数组,这个时候你会获得一个虚拟地址的范围,这时页表就会保存你的虚拟地址范围和映射到内存中的物理地址范围。同时页表还会保存数据的一些相关信息,比方说“可读可写”、“只可读不可写”。
这样当你通过地址访问数组的时候,操作系统会就会在页表中找有没有该虚拟地址和物理地址的对应关系。如果地址正常,页表中一定会有映射关系存在,这样就可以正常访问数组。如果发生越界情况,操作系统在页表中找不到该虚拟地址和物理地址的对应关系,说明非法访问,然后报错。
还有如果当你试图更改一个不可写的数据时,操作系统会判断当前数据是否可写,如果不可写就会报错。比方说:字符串、常量等等…
虚拟内存的实现需要建立在离散分配的内存管理方式的基础上。内存需要实现分页或分段的内存管理形式:
分段、分页是针对物理内存进行的管理方式。将物理内存划分好后与虚拟内存进行映射对应。
内存的管理有4种方式:
简单来说:页是物理单位,段是逻辑单位。分页可以有效提高内存利用率,分段可以更好满足用户需求。
区别:
段、页、页框、页表、页表项_页框号_biggerbugger的博客-CSDN博客
top命令作为 Linux下最常用的性能分析工具之一,可以监控、收集进程的CPU、IO存使用情况。比如我们可以通过top命令获得个进程使用了多少虚拟内存(VIRT)、物理内存(RES)、共享内存(SHR)
2.1 top命令中ⅥRT、RES和SHR的含义
VIRT的含义。搞清楚了虚拟内存的概念之后解释ⅥRT的含义就很简单了。ⅥRT表示的是进程虚拟内存空间大小。对应到图1中的进程A来说就是A1、A2、A3、A4以及灰色部分所有空间的总和.也就是说VIRT包含了在已经映射到物理内存空间的部分和尚未映射到物理内存空间的部分和。
RES的含义。指进程虚拟內存空间中已经映射到物理內存空间的那部分的大小。对应到图1中的进程A来说就是A1、A2、A3以及A4几个部分空间的总和。所以说,看进程在运行过程中占了多少内存应该看RES的值而不是VIRT的值。
SHR的含义。SHR是 share(共享)的缩写,它表示的是进程占用的共享内存大小。在上图1中我们看到进程A虚拟内存空间中的A4和进程B虚拟内存空间中的B3都映射到了物理内存空间的A4/B3。为什么会出现这样的情况呢?其实我们写的程序会依赖于很多外部的动态库(.so),比如libc.so、libd.so等等。这些动态库在内存中仅仅会保存/映射一份,如果某个进程运行时需要这个动态库,那么动态加载器会将这块内存映到对应进程的虚拟内存空间中。多个进程之间通过共享内存的方式相互通信也会出现这样的凊况。这么一来,就会出现不同进程的虚拟内存空间会映射到相同的物理内存空间。这部分物理内存空间其实是被多个进程所共享的,所以我们将他们称为共享内存,用SHR来表示。某个进程占用的内存除了和别的进程共享的内存之外就是自己的独占内存了。所以要计算进程独占内存的大小只要用RES的值减去SHR值即可 。
————————————————
原文链接:https://blog.csdn.net/qq_41687938/article/details/120479067
因为发生了缺页,因此可能会出现使用页面置换算法的情况,
缺页中断,就是要访问的页不在主存,需要操作系统将其调入主存后再进行访问。
当发生缺页中断时,如果当前内存中并没有空闲的页面,操作系统就必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。用来决定淘汰哪一页的规则叫做页面置换算法。
(1)快表:
为了解决虚拟地址到物理地址的转换速度,操作系统在页表方案基础之上引入了 快表 来加速虚拟地址到物理地址的转换。我们可以把快表理解为一种特殊的高速缓冲存储器(Cache),其中的内容是页表的一部分或者全部内容。
(2)多级页表:
引入多级页表的主要目的是为了避免把全部页表一直放在内存中占用过多空间,特别是那些根本就不需要的页表就不需要保留在内存中。多级页表属于时间换空间的典型场景。