精华内容
下载资源
问答
  • 虚拟内存与物理内存

    2020-05-25 18:30:30
    操作系统有虚拟内存与物理内存的概念。在很久以前,还没有虚拟内存概念的时候,程序寻址用的都是物理地址。程序能寻址的范围是有限的,这取决于CPU的地址线条数。比如在32位平台下,寻址的范围是2^32也就是4G。并且...

    操作系统有虚拟内存与物理内存的概念。在很久以前,还没有虚拟内存概念的时候,程序寻址用的都是物理地址。程序能寻址的范围是有限的,这取决于CPU的地址线条数。比如在32位平台下,寻址的范围是2^32也就是4G。并且这是固定的,如果没有虚拟内存,且每次开启一个进程都给4G的物理内存,就可能会出现很多问题:

    • 因为我的物理内存时有限的,当有多个进程要执行的时候,都要给4G内存,很显然你内存小一点,这很快就分配完了,于是没有得到分配资源的进程就只能等待。当一个进程执行完了以后,再将等待的进程装入内存。这种频繁的装入内存的操作是很没效率的
    • 由于指令都是直接访问物理内存的,那么我这个进程就可以修改其他进程的数据,甚至会修改内核地址空间的数据,这是我们不想看到的
    • 因为内存时随机分配的,所以程序运行的地址也是不正确的。

    于是针对上面会出现的各种问题,虚拟内存就出来了。

    在之前一篇文章中进程分配资源介绍过一个进程运行时都会得到4G的虚拟内存。这个虚拟内存你可以认为,每个进程都认为自己拥有4G的空间,这只是每个进程认为的,但是实际上,在虚拟内存对应的物理内存上,可能只对应的一点点的物理内存,实际用了多少内存,就会对应多少物理内存。

    进程得到的这4G虚拟内存是一个连续的地址空间(这也只是进程认为),而实际上,它通常是被分隔成多个物理内存碎片,还有一部分存储在外部磁盘存储器上,在需要时进行数据交换。

    进程开始要访问一个地址,它可能会经历下面的过程

    1. 每次我要访问地址空间上的某一个地址,都需要把地址翻译为实际物理内存地址
    2. 所有进程共享这整一块物理内存,每个进程只把自己目前需要的虚拟地址空间映射到物理内存上
    3. 进程需要知道哪些地址空间上的数据在物理内存上,哪些不在(可能这部分存储在磁盘上),还有在物理内存上的哪里,这就需要通过页表来记录
    4. 页表的每一个表项分两部分,第一部分记录此页是否在物理内存上,第二部分记录物理内存页的地址(如果在的话)
    5. 当进程访问某个虚拟地址的时候,就会先去看页表,如果发现对应的数据不在物理内存上,就会发生缺页异常
    6. 缺页异常的处理过程,操作系统立即阻塞该进程,并将硬盘里对应的页换入内存,然后使该进程就绪,如果内存已经满了,没有空地方了,那就找一个页覆盖,至于具体覆盖的哪个页,就需要看操作系统的页面置换算法是怎么设计的了。

    关于虚拟内存与物理内存的联系,下面这张图可以帮助我们巩固。

    页表的工作原理如下图

    1. 我们的cpu想访问虚拟地址所在的虚拟页(VP3),根据页表,找出页表中第三条的值.判断有效位。 如果有效位为1,DRMA缓存命中,根据物理页号,找到物理页当中的内容,返回**。**
    2. 若有效位为0,参数缺页异常,调用内核缺页异常处理程序。内核通过页面置换算法选择一个页面作为被覆盖的页面,将该页的内容刷新到磁盘空间当中。然后把VP3映射的磁盘文件缓存到该物理页上面。然后页表中第三条,有效位变成1,第二部分存储上了可以对应物理内存页的地址的内容。
    3. 缺页异常处理完毕后,返回中断前的指令,重新执行,此时缓存命中,执行1。
    4. 将找到的内容映射到告诉缓存当中,CPU从告诉缓存中获取该值,结束。

    再来总结一下虚拟内存是怎么工作的

    当每个进程创建的时候,内核会为进程分配4G的虚拟内存,当进程还没有开始运行时,这只是一个内存布局。实际上并不立即就把虚拟内存对应位置的程序数据和代码(比如.text .data段)拷贝到物理内存中,只是建立好虚拟内存和磁盘文件之间的映射就好(叫做存储器映射)。这个时候数据和代码还是在磁盘上的。当运行到对应的程序时,进程去寻找页表,发现页表中地址没有存放在物理内存上,而是在磁盘上,于是发生缺页异常,于是将磁盘上的数据拷贝到物理内存中。

    另外在进程运行过程中,要通过malloc来动态分配内存时,也只是分配了虚拟内存,即为这块虚拟内存对应的页表项做相应设置,当进程真正访问到此数据时,才引发缺页异常。

    可以认为虚拟空间都被映射到了磁盘空间中(事实上也是按需要映射到磁盘空间上,通过mmap,mmap是用来建立虚拟空间和磁盘空间的映射关系的)

    利用虚拟内存机制的优点

    1. 既然每个进程的内存空间都是一致而且固定的(32位平台下都是4G),所以链接器在链接可执行文件时,可以设定内存地址,而不用去管这些数据最终实际内存地址,这交给内核来完成映射关系
    2. 当不同的进程使用同一段代码时,比如库文件的代码,在物理内存中可以只存储一份这样的代码,不同进程只要将自己的虚拟内存映射过去就好了,这样可以节省物理内存
    3. 在程序需要分配连续空间的时候,只需要在虚拟内存分配连续空间,而不需要物理内存时连续的,实际上,往往物理内存都是断断续续的内存碎片。这样就可以有效地利用我们的物理内存
    展开全文
  • 虚拟内存与物理内存的联系与区别

    万次阅读 多人点赞 2018-08-30 11:55:36
    操作系统有虚拟内存与物理内存的概念。在很久以前,还没有虚拟内存概念的时候,程序寻址用的都是物理地址。程序能寻址的范围是有限的,这取决于CPU的地址线条数。比如在32位平台下,寻址的范围是2^32也就是4G。并且...

    操作系统有虚拟内存与物理内存的概念。在很久以前,还没有虚拟内存概念的时候,程序寻址用的都是物理地址。程序能寻址的范围是有限的,这取决于CPU的地址线条数。比如在32位平台下,寻址的范围是2^32也就是4G。并且这是固定的,如果没有虚拟内存,且每次开启一个进程都给4G的物理内存,就可能会出现很多问题:

    • 因为我的物理内存时有限的,当有多个进程要执行的时候,都要给4G内存,很显然你内存小一点,这很快就分配完了,于是没有得到分配资源的进程就只能等待。当一个进程执行完了以后,再将等待的进程装入内存。这种频繁的装入内存的操作是很没效率的
    • 由于指令都是直接访问物理内存的,那么我这个进程就可以修改其他进程的数据,甚至会修改内核地址空间的数据,这是我们不想看到的
    • 因为内存时随机分配的,所以程序运行的地址也是不正确的。

    于是针对上面会出现的各种问题,虚拟内存就出来了。

    在之前一篇文章中进程分配资源介绍过一个进程运行时都会得到4G的虚拟内存。这个虚拟内存你可以认为,每个进程都认为自己拥有4G的空间,这只是每个进程认为的,但是实际上,在虚拟内存对应的物理内存上,可能只对应的一点点的物理内存,实际用了多少内存,就会对应多少物理内存。

    进程得到的这4G虚拟内存是一个连续的地址空间(这也只是进程认为),而实际上,它通常是被分隔成多个物理内存碎片,还有一部分存储在外部磁盘存储器上,在需要时进行数据交换。

    进程开始要访问一个地址,它可能会经历下面的过程

    1. 每次我要访问地址空间上的某一个地址,都需要把地址翻译为实际物理内存地址
    2. 所有进程共享这整一块物理内存,每个进程只把自己目前需要的虚拟地址空间映射到物理内存上
    3. 进程需要知道哪些地址空间上的数据在物理内存上,哪些不在(可能这部分存储在磁盘上),还有在物理内存上的哪里,这就需要通过页表来记录
    4. 页表的每一个表项分两部分,第一部分记录此页是否在物理内存上,第二部分记录物理内存页的地址(如果在的话)
    5. 当进程访问某个虚拟地址的时候,就会先去看页表,如果发现对应的数据不在物理内存上,就会发生缺页异常
    6. 缺页异常的处理过程,操作系统立即阻塞该进程,并将硬盘里对应的页换入内存,然后使该进程就绪,如果内存已经满了,没有空地方了,那就找一个页覆盖,至于具体覆盖的哪个页,就需要看操作系统的页面置换算法是怎么设计的了。

     

    关于虚拟内存与物理内存的联系,下面这张图可以帮助我们巩固。

    页表的工作原理如下图

    1. 我们的cpu想访问虚拟地址所在的虚拟页(VP3),根据页表,找出页表中第三条的值.判断有效位。 如果有效位为1,DRMA缓存命中,根据物理页号,找到物理页当中的内容,返回
    2. 若有效位为0,参数缺页异常,调用内核缺页异常处理程序。内核通过页面置换算法选择一个页面作为被覆盖的页面,将该页的内容刷新到磁盘空间当中。然后把VP3映射的磁盘文件缓存到该物理页上面。然后页表中第三条,有效位变成1,第二部分存储上了可以对应物理内存页的地址的内容。
    3. 缺页异常处理完毕后,返回中断前的指令,重新执行,此时缓存命中,执行1。
    4. 将找到的内容映射到告诉缓存当中,CPU从告诉缓存中获取该值,结束。

     

    再来总结一下虚拟内存是怎么工作的

    当每个进程创建的时候,内核会为进程分配4G的虚拟内存,当进程还没有开始运行时,这只是一个内存布局。实际上并不立即就把虚拟内存对应位置的程序数据和代码(比如.text .data段)拷贝到物理内存中,只是建立好虚拟内存和磁盘文件之间的映射就好(叫做存储器映射)。这个时候数据和代码还是在磁盘上的。当运行到对应的程序时,进程去寻找页表,发现页表中地址没有存放在物理内存上,而是在磁盘上,于是发生缺页异常,于是将磁盘上的数据拷贝到物理内存中。

    另外在进程运行过程中,要通过malloc来动态分配内存时,也只是分配了虚拟内存,即为这块虚拟内存对应的页表项做相应设置,当进程真正访问到此数据时,才引发缺页异常。

    可以认为虚拟空间都被映射到了磁盘空间中(事实上也是按需要映射到磁盘空间上,通过mmap,mmap是用来建立虚拟空间和磁盘空间的映射关系的)

     

    利用虚拟内存机制的优点 

    1. 既然每个进程的内存空间都是一致而且固定的(32位平台下都是4G),所以链接器在链接可执行文件时,可以设定内存地址,而不用去管这些数据最终实际内存地址,这交给内核来完成映射关系
    2. 当不同的进程使用同一段代码时,比如库文件的代码,在物理内存中可以只存储一份这样的代码,不同进程只要将自己的虚拟内存映射过去就好了,这样可以节省物理内存
    3. 在程序需要分配连续空间的时候,只需要在虚拟内存分配连续空间,而不需要物理内存时连续的,实际上,往往物理内存都是断断续续的内存碎片。这样就可以有效地利用我们的物理内存

     

    展开全文
  • 虚拟内存与物理内存 为什么要有虚拟内存??? 1.每个进程有独立的虚拟地址空间,进程访问的虚拟地址并不是真正的物理地址(每个进程都假设自己看到的是完整的从0开始的内存) 2.程序可以使用一系列虚拟地址来访问大于...

    内存杂谈

    虚拟内存与物理内存

    为什么要有虚拟内存???

    1.每个进程有独立的虚拟地址空间,进程访问的虚拟地址并不是真正的物理地址(每个进程都假设自己看到的是完整的从0开始的内存)
    2.程序可以使用一系列虚拟地址来访问大于可用物理内存的内存缓冲区。当物理内存的供应量变小时,内存管理器会将物理内存页(通常大小为 4 KB)保存到磁盘文件。数据或代码页会根据需要在物理内存与磁盘之间移动。(如linux swap 分区)

    如何实现虚拟内存???

    虚拟内存与物理内存存在映射关系, 这样"逻辑上的虚拟内存连续"在"实际物理内存上"其实是不连续的.
    虚拟内存通过 MMU(映射算法)与页表组成, MMU操作的最小基本单位为 页.

    内存碎片

    现代OS如何避免内存碎片???

    基础

    1. 页,页面,与框
      https://blog.csdn.net/displayMessage/article/details/80905810
    2. 页中断

    Linux 通过 buddy system 避免内存碎片

    即使合并内存, 减少内存碎片的产生, 详情百度即可

    什么是内存碎片

    碎片只会在虚拟内存中产生,是不会映射到物理内存上的。
    碎片只会在虚拟内存中产生,是不会映射到物理内存上的。
    碎片只会在虚拟内存中产生,是不会映射到物理内存上的。
    重要的事说三遍
    采用分区式存储管理的系统,在储存分配过程中产生的、不能供用户作业使用的主存里的小分区称成“内存碎片”。内存碎片分为内部碎片和外部碎片。

    内存的静态分配与动态分配

    内存分配有静态分配和动态分配两种。静态分配在程序编译链接时分配的大小和使用寿命就已经确定,而应用上要求操作系统可以提供给进程运行时申请和释放任意大小内存的功能,这就是内存的动态分配, 动态内存会导致内存碎片的产生。

    内部碎片与外部碎片

    内部碎片: 众所周知,内存需要对齐(起点落在 4 的倍数上), 所以如果申请27byte内存实际上会给分配28byte内存。 eg: linux 最小页面长度为 4096 byte, 用 c 语言malloc 一个 char(1byte) 的空间, 则必须最少申请 4k 的空间吗??
    外部碎片: 频繁的申请与释放内存,会导致有很多不连续的可用的小内存在已分配的页面中, 此时如果申请一片较大的内存(申请的内存是连续的),即使这些小内存加起来 > 要申请的内存,也不能申请成功(因为这些小的可用内存不是连续的).

    c/c++ 如何避免内存碎片

    所有语言都会有内存碎片,内存碎片只能减少而不能避免.
    减少内存碎片可以用第三方库来实现.

    1. 少用动态内存分配的函数(尽量使用栈空间)
    2. 分配内存和释放的内存尽量在同一个函数中
    3. 申请内存的大小尽量为 2^n, 以避免内部内存碎片, 而不要反复申请小内存(少进行内存的分割, 得益于os用 buddy system来管理内存)
    4. 不要频繁的申请小内存
    5. 尽可能少地申请空间。
    6. 尽量少使用堆上的内存空间~
    7. 做内存池,也就是自己一次申请一块足够大的空间,然后自己来管理,用于大量频繁地new/delete操作。(我们可以推断出 自动回收机制也是有弊端的)

    eg: linux 最小页面长度为 4096 byte, 用 c 语言malloc 一个 char(1byte) 的空间, 则必须最少申请 4k 的空间吗??
    进程占有逻辑上的全部内存(虚拟内存),malloc 占用的是堆区的空间 . 在申请小内存时(以 glibc 中 小于128kb时), 仅仅移动brk指针向高地址
    //会在第一次使用时产生页中断,才建立映射关系(延时映射机制).
    答: 只用16byte(或许包含了内存对齐和其他的数据),远远没有使用 4kb 的内存.(这个问题目前还没有想出来答案)

    gcc中 vector 的默认扩增倍数k为什么为2而不是常量??? 2是否是最优解
    1. 为什么不是常量???
      答: 进行 n 次push_back , 在内存复制方面,k 为倍数要比k为常量的时间复杂度小的多.

    2. 用 2 有什么好处???
      答:

    3. 2 倍不是最优解???
      答:倍数为1.618为最优,由于vector使用copy扩增会重新申请一块大的内存然后再, 将对象复制进新的内存,然后释放掉原来的内存。那么在下次扩充的时候,由于每次申请的都比之前所有释放的空间加起来都大(k==2的特性),就导致之前释放的的内存不能用, 详情见:
      https://www.zhihu.com/question/36538542/answer/67929747

    //2. 是为了防止内部内存碎片的发生. 内存以2^n对齐, 如果不为2^n,则

    展开全文
  • 1.虚拟内存与物理内存 每一个物理内存的大小是4KB,每个进程由4GB的虚拟内存 虚拟内存与物理内存的关系: 每个进程的4GB虚拟内存分为高2G和低2G,而低2G是进程实际使用的空间,高2G是内核用的(而且低2G中的前64KB...

    1.虚拟内存与物理内存

    每一个物理内存的大小是4KB,每个进程由4GB的虚拟内存

    虚拟内存与物理内存的关系:

    在这里插入图片描述

    每个进程的4GB虚拟内存分为高2G和低2G,而低2G是进程实际使用的空间,高2G是内核用的(而且低2G中的前64KB用户程序也不能使用),所以一个进程实际的空间大小为2G(不包括前64KB)

    物理内存:实际可使用的内存大小

    可供使用的物理内存:

    ​ MmNumberOfPhysicalPages * 4 = 物理内存

    ​ 虚拟内存(硬盘)

    能够识别的物理内存:

    ​ 32位系统最多可以识别物理内存为64G,但由于操作系统的限制,比如XP,只能识别4G(Windows 2003服务器版本 可以识别4G以上)

    在这里插入图片描述

    正是由于这个物理页挪来挪去,才让人们感到内存挺大,实际不大。

    展开全文
  • 虚拟内存 物理内存物理内存虚拟内存进程要访问地址的过程 物理内存 物理内存实际上是 CPU中能直接寻址的地址线条数。由于物理内存是有限的,例如32位平台下,寻址的大小是4G,并且是固定的。内存很快就会被分配完...
  • 虚拟内存与物理内存的关系

    千次阅读 2019-05-25 18:45:35
    操作系统有虚拟内存与物理内存的概念。在很久以前,还没有虚拟内存概念的时候,程序寻址用的都是物理地址。程序能寻址的范围是有限的,这取决于CPU的地址线条数。比如在32位平台下,寻址的范围是2^32也就是4G。并且...
  • 物理内存空间大小受限的时期,虚拟内存的概念被提了出来,其提供了一种对主存的抽象。虚拟内存机制使得对于每一个进程,其能够提供一个足够大、私有的地址空间。虚拟内存主要的三大能力: 主存是一个对存储在磁盘...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,599
精华内容 1,439
关键字:

虚拟内存与物理内存