精华内容
下载资源
问答
  • 分析了嵌入式系统虚拟内存管理应具有的功能特点,提出了一种具有处理器无关标准编程接口的嵌入式虚拟内存管理平台的实现方法。
  • 虚拟内存管理

    千次阅读 2019-07-08 23:01:09
    虚拟内存管理这是一种利用虚拟存储器来逻辑扩充物理内存的管理方式。其基本思想是用软硬件技术把内存与外存这两级存储器当成一级存储器来用,从而给用户提供了一个比内存也比任何应用程序大得多的虚拟存储器,使得...

    虚拟内存管理这是一种利用虚拟存储器来逻辑扩充物理内存的管理方式。其基本思想是用软硬件技术把内存与外存这两级存储器当成一级存储器来用,从而给用户提供了一个比内存也比任何应用程序大得多的虚拟存储器,使得用户编程时再也不用考虑内存大小的限制了,给用户编程带来极大的方便。

    传统存储管理方式的特征

    段页式的内存管理策略都是为了同时将多个进程保存在内存中以便允许多道程序设计。它们都具有以下两个共同的特征:

    1)一次性:作业必须一次性全部装入内存后,方能开始运行。这会导致两种情况发生:①当作业很大,不能全部被装入内存时,将使该作业无法运行:②当大量作业要求运行时,由于内存不足以容纳所有作业,只能使少数作业先运行,导致多道程序度的下降。

    2)驻留性:作业被装入内存后,就一直驻留在内存中,其任何部分都不会被换出,直至作业运行结束。运行中的进程,会因等待I/O而被阻塞,可能处于长期等待状态。

    由以上分析可知,许多在程序运行中不用或暂时不用的程序(数据)占据了大量的内存空间,而一些需要运行的作业又无法装入运行,显然浪费了宝贵的内存资源。

    局部性原理

    局部性原理:指程序在执行过程中的一个较短时期内,所执行的指令地址和指令的操作数地址,分别局限于一定区域。

    局部性主要表现:

    时间局部性:是指一段指令在某一时间段内会被反复执行。即程序某一部分的数据或指令被重复性地访问,它们对应于程序结构中的循环、子程序、常用到的变量及数据等 ;

    空间局部性:是指一旦某一个存储单元被访问,那么它附近的单元也将很快被访问。这对应于程序结构中的顺序执行的指令、线性数据结构以及在相邻位置存放的数据或变量等。而程序中的分支和调用子程序只是将程序的访问空间从一处移到另外一处,仍具有局部性。

    排他性:程序运行不但体现在时间、空间的局部性,还体现在某些程序段执行的排他性。

    即程序设计者编程时要考虑程序执行时所能遇到的各种情况,但具体到一次程序的执行,并不会发生所有的状况。因而某些程序段在进程整个运行期间,可能根本不使用,如出错处理、分支语句等。因而,没有用到的程序段就不必调入内存。另外,有些程序段仅执行一次,以后就再也不会用到,这样的程序段也没有必要一直占用内存空间。

    综上所述:程序只要装入内存一部分就可以运行,当用到不在内存的部分时,再将其装入内存。换句话就是说程序全部装入内存并不是程序运行的必要条件。

    虚拟内存的定义和特征

    虚拟存储器

    基于局部性原理,在程序装入时,可以将程序的一部分装入内存,而将其余部分留在外存,就可以启动程序执行。在程序执行过程中,当所访问的信息不在内存时,由操作系统将所需要的部分调入内存,然后继续执行程序。另一方面,操作系统将内存中暂时不使用的内容换出到外存上,从而腾出空间存放将要调入内存的信息。这样,系统好像为用户提供了一个比实际内存大得多的存储器,称为虚拟存储器。

    之所以将其称为虚拟存储器,是因为这种存储器实际上并不存在,只是由于系统提供了部分装入、请求调入和置换功能后(对用户完全透明),给用户的感觉是好像存在-一个比实际物理内存大得多的存储器.虚拟存储器的大小由计算机的地址结构决定,并非是内存和外存的简单相加。
    虚拟存储器有以下三个主要特征:

    • 多次性,是指无需在作业运行时- 次性地全部装入内存,而是允许被分成多次调入内存运行。
    • 对换性,是指无需在作业运行时一直常驻内存,而是允许在作业的运行过程中,进行换进和换出。
    • 虚拟性,是指从逻辑上扩充内存的容量,使用户所看到的内存容量,远大于实际的内存容量。

    虚拟内存的实现

    虚拟内存中,允许将-一个作业分多次调入内存。采用连续分配方式时,会使相当一部分内存空间都处于暂时或“永久”的空闲状态,造成内存资源的严重浪费,而且也无法从逻辑上扩大内存容量。因此,虛拟内存的实现需要建立在离散分配的内存管理方式的基础上。

    虚拟内存的实现有以下三种方式:

    • 请求分页存储管理。
    • 请求分段存储管理。
    • 请求段页式存储管理。

    不管哪种方式,都需要有一-定的硬件支持。一般需要的支持有以下几个方面:

    • 一定容量的内存和外存。
    • 页表机制(或段表机制),作为主要的数据结构。
    • 中断机构,当用户程序要访问的部分尚未调入内存,则产生中断。
    • 地址变换机构,逻辑地址到物理地址的变换。

    请求分页存储管理方式

    为了实现请求分页,系统必须提供- -定的硬件支持。除了需要- -定容量的内存及外存的计算
    机系统,还需要有页表机制、缺页中断机构和地址变换机构。

    1.页表机制

    请求分页系统的页表机制不同于基本分页系统,请求分页系统在.一个作业运行之前不要求全部一次性调入内存,因此在作业的运行过程中,必然会出现要访问的页面不在内存的情况,如何发现和处理这种情况是请求分页系统必须解决的两个基本问题。为此,在请求页表项中增加了四个字段。

    增加的四个字段说明如下:

    • 状态位P:用于指示该页是否已调入内存,供程序访问时参考。
    • 访问字段A:用于记录本页在- 段时间内被访问的次数,或记录本页最近已有多长时间未被访问,供置换算法换出页面时参考。
    • 修改位M:标识该页在调入内存后是否被修改过。
    • 外存地址:用于指出该页在外存上的地址,通常是物理块号,供调入该页时参考。

    2.缺页中断机构

    在请求分页系统中,每当所要访问的页面不在内存时,便产生-一个缺页中断,请求操作系统将所缺的页调入内存。此时应将缺页的进程阻塞(调页完成唤醒),如果内存中有空闲块,则分配-一个块,将要调入的页装入该块,并修改页表中相应页表项,若此时内存中没有空闲块,则要淘汰某页(若被淘汰页在内存期间被修改过,则要将其写回外存)。

    3.地址变换机构

    请求分页系统中的地址变换机构,是在分页系统地址变换机构的基础上,为实现虚拟内存,又增加了某些功能而形成的。

                                                    

    页面置换算法

    最佳置换算法(OPT)

    方法:根据未来使用情况将未来的近期里不用的页替换出去。
    实现:

    • 确定要替换的时刻T。
    • 找出主存中每个页将来要用到的时刻Ti。
    • Ti 减 T最大的页将被替换。

    特点:命中率高,但难于实现(必须运行一遍,才能知道未来的时刻ti),是理想算法,用于评价其它替换算法。

                           

    发生了6次页面置换,9次缺页中断,总访问次数20次,缺页率9/20=45% 。

    先进先出(FIFO)页面置换算法

    优先淘汰最早进入内存的页面,亦即在内存中驻留时间最久的页面。该算法实现简单,只需把调入内存的页面根据先后次序链接成队列,设置- 一个指针总指向最早的页面。但该算法与进程实际运行时的规律不适应,因为在进程中,有的页面经常被访问。

                            

    发生了12次页面置换,15次缺页中断,总访问次数20次,缺页率15/20=75% 。

    最近最久未使用(LRU)换算法

    方法:近期最久未访问过的页作为被替换的页
    实现:赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间t,当须淘汰一个页面时,选择现有页面中其t值最大的页面予以淘汰。
    特点:计数器硬件较少,主存页面表可由软硬件实现修改,根据“历史”预测“未来”。

                               

    发生了9次页面置换,12次缺页中断,总访问次数20次,缺页率12/20=60% 。

    LRU置换算法的硬件支持:

    • 每个页面设立移位寄存器:被访问时左边最高位置1,定期右移并且最高位补0,于是寄存器数值最小的是最久未使用页面。
    • 一个特殊的栈:把被访问的页面移到栈顶,于是栈底的是最久未使用页面。

    Clock置换算法

    每页设置一位访问位,若该页被访问则其访问位被置1;
    内存中所有页面都通过链接指针链接成一个循环队列,置换时采用一个指针,从当前指针位置开始按地址先后检查各页,寻找访问位为0的页面作为被置换页;
    指针经过的访问位为1的页都将其访问位置0,最后指针停留在被置换页的下一个页。

    简单的Clock置换算法

                                                           

    页面分配策略

    駐留集大小

    对于分页式的虚拟内存,在准备执行时,不需要也不可能把-.个进程的所有页都读取到主存,因此,操作系统必须决定读取多少页。也就是说,给特定的进程分配多大的主存空间,这需要考虑以下几点:

    1. 分配给一个进程的存储量越小,在任可时候驻留在主存中的进程数就越多,从而可以提高处理机的时间利用效率。
    2. 如果一个进程在主存中的页数过少,尽管有局部性原理,页错误率仍然会相对较高。
    3. 如果页数过多,由于局部性原理,给特定的进程分配更多的主存空间对该进程的错误率没有明显的影响。

    固定分配、局部置换

    •  为每个进程分配固定页数的内存空间、且运行过程中不变。
    •  当进程缺页时,只能从该进程在内存的几个页面中选出一页换出,然后再调入一页,保证进程的页数不变。

    可变分配、全局置换

    • 系统开始先为每个进程分配一定数目的物理块。整个系统有一空闲物理块链,当某进程缺页时,系统从空闲链中选出一块分配给进程。
    • 空闲链为空时,OS从所有进程的页面中权衡选择一页换出。

    可变分配、局部置换

    • 分配同上,但进程缺页时,只能从该进程在内存的页面中选出一页换出。

    调入页面的时机

    为确定系统将进程运行时所缺的页面调入内存的时机,可采取以下两种调页策略:

    (1)预调页策略。根据局部性原理,- -次调入若千个相邻的页可能会比一次调入- -页更高效。但如果调入的一批页面中大多数都未被访问,则又是低效的。所以就需要采用以预测为基础的预调页策略,将预计在不久之后便会被访问的页面预先调入内存。但目前预调页的成功率仅约50%。故这种策略主要用于进程的首次调入时,由程序员指出应该先调入哪些页。

    (2)请求调页策略。进程在运行中需要访问的页面不在内存而提出请求,由系统将所需页面调入内存。由这种策略调入的页- -定会被访问, 且这种策略比较易于实现,故在目前的虚拟存储器中大多采用此策略。它的缺点在于每次只调入一页,调入调出页面数多时会花费过多的I/O开销。

    预调入实际上就是运行前的调入,请求调页实际上就是运行期间调入。一般情况下,两种调页策略会同时使用。

    从何处调入页面

    请求分页系统中的外存分为两部分:用于存放文件的文件区和用于存放对换页面的对换区。对换区通常是采用连续分配方式,而文件区采用离散分配方式,故对换区的磁盘IO速度比文件区的更快。这样从何处调入页面有三种情况:

    (1)系统拥有足够的对换区空间:可以全部从对换区调入所需页面,以提高调页速度。为此,在进程运行前,需将与该进程有关的文件从文件区复制到对换区。

    (2)系统缺少足够的对换区空间:凡不会被修改的文件都直接从文件区调入;而当换出这些页面时,由于它们未被修改而不必再将它们换出。但对于那些可能被修改的部分,在将它们换出时须调到对换区,以后需要时再从对换区调入(这是因为读的速度比写的速度快)。

    (3)UNIX方式:与进程有关的文件都放在文件区,故未运行过的页面,都应从文件区调入。曾经运行过但又被换出的页面,由于是被放在对换区,因此F次调入时应从对换区调入。进程请求的共享页面若被其他进程调入内存,则无需再从对换区调入。

    抖动

    在页面置换过程中的一种最糟糕的情形是,刚刚换出的页面马上又要换入主存,刚刚换入的页面马上就要换出主存,这种频繁的页面调度行为称为抖动,或颠簸。如果一个进程在换页 上用的时间多于执行时间,那么这个进程就在颠簸。

    频繁的发生缺页中断(抖动), 其主要原因是某个进程频繁访问的页面数目高于可用的物理页帧数目。虚拟内存技术可以在内存中保留更多的进程以提高系统效率。在稳定状态,几乎主存的所有空间都被进程块占据,处理机和操作系统可以直接访问到尽可能多的进程。但如果管理不当,处理机的大部分时间都将用于交换块,即请求调入页面的操作,而不是执行进程的指令,这就会大大降低系统效率。

                                                    

    工作集

    工作集(或驻留集)是指在某段时间间隔内,进程要访问的页面集合。经常被使用的页面需要在工作集中,而长期不被使用的页面要从工作集中被丢弃。为了防止系统出现抖动现象,需要选择合适的工作集大小。

    工作集模型的原理是:让操作系统跟踪每个进程的工作集,并为进程分配大于其工作集的物理块。如果还有空闲物理块,则可以再调一个进程到内存以增加多道程序数。如果所有工作集之和增加以至于超过了可用物理块的总数,那么操作系统会暂停一个进程, 将其页面调出并且将其物理块分配给其他进程,防止出现抖动现象。

    正确选择工作集的大小,对存储器的利用率和系统吞吐量的提高,都将产生重要影响。

    最后总结

    虚拟内存管理的优点:

    1. 主存利用率比较高:平均每个用户作业只浪费一半的页空间,内存规范易于管理。
    2. 对磁盘管理比较容易:因为页的大小一般取磁盘物理块大小的整数倍。
    3. 地址映射和变换的速度比较快:在把用户程序装入到主存储器的过程中,只要建立用户程序的虚页号与主存储器的实页号之间的对应关系即可(拼接得到物理地址),不必使用整个主存的地址长度,也不必考虑每页的长度等
    4. 大程序:可在较小的可用内存中执行较大的用户程序;
    5. 大的用户空间:提供给用户可用的虚拟内存空间通常大于物理内存(real memory)
    6. 并发:可在内存中容纳更多程序并发执行;
    7. 易于开发:与覆盖技术比较,不必影响编程时的程序结构

    虚拟内存管理的缺点:

    (1)程序的模块化性能不好。
    由于用户程序是强制按照固定大小的页来划分的,而程序段的实际长度一般是不固定的。因此,虚拟页式存储器中一页通常不能表示一个完整的程序功能。一页可能只是一个程序段中的一部分,也可能在一页中包含了两个或两个以上程序段。
    (2)页表很长,需要占用很大的存储空间。
    通常,虚拟存储器中的每一页在页表中都要占一个页表项。假设有一个虚拟页式存储器,它的虚拟存储空间大小为4GB,每一页的大小为1KB,则页表的容量为4M(个页表项)。如果每个页表项占用4个字节,则页表的存储容量为16MB。

    总结:总容量不超过物理内存和外存交换区容量之和。其运行速度接近于内存,每位的成本又接近于外存,是一种性能非常优越的存储管理技术。

     

    可能有的小问题

    1 虚拟内存管理发生在什么时候?

    首先当cpu发出一个虚拟地址请求后,把虚拟地址送给MMU处理。

    MMU得到地址后,通过计算得到页号/段号,先判断是否有读写权限,如果没有就返回错误,如果有再查询表(STL表/普通页表),

    • 如果表中没有该页/该段,就产生一个缺页中中断,虚拟内存管理技术就会通过一系列算法来把缺少的页从外存中取出来,放到内存中。
    • 如果表中有该页,那就通过表计算得到物理地址(即内存中的地址)。

    CPU得到物理地址后就可以对内存进行读写操作。

    2 为什么有时候多个的进程中有相同的虚拟地址,难道它们不会打架吗?

    因为每个用户都有一份属于自己的页表,所以即使虚拟地址相同,但是对应的物理地址不同,即使物理地址相同,通过虚拟存储即使对内存中的某些页进行替换操作。

     

     

     

     

     

     

    展开全文
  • 3.2 虚拟内存管理

    千次阅读 2020-10-21 22:01:38
    3.2.1 虚拟内存的基本概念 1、传统存储管理方式的特征 1)一次性: 作业必须一次性全部装入内存后,才开始运行 2)驻留性:作业被装入内存后,就一直驻留在内存中 2、局部性原理: 时间局部性和空间局部性 时间局部...

    3.2.1 虚拟内存的基本概念


    1、传统存储管理方式的特征

    1)一次性: 作业必须一次性全部装入内存后,才开始运行

    2)驻留性:作业被装入内存后,就一直驻留在内存中

    2、局部性原理: 时间局部性和空间局部性

    时间局部性:程序中的某条指令一旦执行,不久后该指令可能再次执行
    空间局部性:程序访问了某个存储单元,不久后,其附近的存储单元也被访问。

    3、虚拟存储器的定义和特征

    1)多次性:无需一次将作业全部装入内存,允许被分次调入内存。
    2)对换性: 无需在作业运行时一直常驻内存,允许在作业运行过程中,进行换进和换出。
    3)虚拟性: 从逻辑上扩充内存容量。

    4、虚拟内存技术的实现

    虚拟内存技术的实现需要建立在 离散分配 的内存管理方式的基础之上。

    虚拟内存技术的实现有以下三种方式:

    • 请求分页存储管理
    • 请求分段存储管理
    • 请求段页式存储管理

    3.2.2 请求分页管理方式

    与基本分页管理相比,请求分页管理中,为了实现“请求调页”,操作系统需要知道每个页面是否已经调入内存;如果还没调入,那么也需要知道该页面在外存中存放的位置。

    1、页表机制

    请求分页系统建立在基本分页系统基础之上,为了支持虚拟存储器功能而增加了请求调页功能页面置换功能。请求分页是目前最常用的一种实现虚拟存储器的方法。
    在这里插入图片描述

    ![](https://img-blog.csdnimg.cn/20201021193226693.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zODIyMDc5OQ==,size_16,color_FFFFFF,t_70#pic_center
    2、缺页中断机构

    在请求分页系统中,每当要访问的页面不在内存中时,便产生一个缺页中断,请求系统将所缺的页面调入内存。此时应将缺页的进程阻塞(I/O请求),若此时内存中有空闲块,则将该页调入该块, 若没有空闲块,则要淘汰某页。(若淘汰页面在内存期间被修改过,则要将其写回外存)

    • 在指令执行期间产生和处理中断信号,而非一条指令执行完后,属于内中断

    在这里插入图片描述

    3、地址变换机构

    请求分页存储管理与基本分页存储管理的主要区别:

    在程序执行过程中,当所访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存 (操作系统要提供请求调页功能,将缺失页面从外存调入内存),然后继续执行程序。

    若内存空间不够,由操作系统负责将内存中暂时用不到的信息换出到外存 (操作系统要提供页面置换的功能,将暂时用不到的页面换出外存)。
    相对于分页系统主要增加了关于状态位P的操作。
    在这里插入图片描述
    在这里插入图片描述


    3.2.3 页面调度算法(决定应该换入哪页、换出哪页)

    1)最佳(OPT)置换算法

    每次选择淘汰的页面将是以后永不使用,或者在最长时间内不再被访问的页面,这样可以保证最低的缺页率。
    7在第18次访问才调入,故先替换7
    在这里插入图片描述
    缺页中断未必发生页面置换 只有物理块满了才发生页面置换 (比如前三次发生缺页中断,但未发生页面置换)

    2)先进先出(FIFO)置换算法

    每次选择淘汰的页面最早进入内存的页面

    在这里插入图片描述
    Belady异常--------当为进程分配的物理块数增大时,缺页次数不减反增的异常现象。

    只有FIFO算法会产生Belady异常

    3)最近最久未使用(LRU)置换算法

    每次淘汰的页面是最近最久未使用的页面

    4)时钟(CLOCK)置换算法

    最佳置换算法性OPT能最好,但无法实现
    先进先出置换算法实现简单,但算法性能差
    最近最久未使用置换算法性能好,是最接近OPT算法性能的,但是实现起来需要专门的硬件支持,算法开销大


    简单的时钟置换算法

    在这里插入图片描述


    改进后的时钟置换算法

    优先级:

    • 最近未访问
    • 最近未访问,但修改过
    • 访问过,但未修改
    • 访问过,修改过
      在这里插入图片描述

    在这里插入图片描述


    一轮扫描的情况
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述


    二轮扫描的情况

    第一轮结束后并没有找到(0,0)
    在这里插入图片描述
    第二轮,寻找第一个(0,1),并将扫描过的访问位置为0在这里插入图片描述
    淘汰第一个(0,1)
    在这里插入图片描述


    三轮扫描的情况

    第一轮结束后并没有找到(0,0)
    在这里插入图片描述
    第二轮,寻找第一个(0,1),并将扫描过的访问位置为0,并没有找到

    在这里插入图片描述
    第三轮,寻找第一个(0,0)页面,不修改任何信息
    在这里插入图片描述


    四轮扫描的情况

    第一轮结束后并没有找到(0,0)
    在这里插入图片描述
    第二轮,寻找第一个(0,1),并将扫描过的访问位置为0,并没有找到
    在这里插入图片描述
    第三轮,寻找第一个(0,0)页面,不修改任何信息,并没有找到

    在这里插入图片描述
    第四轮,寻找第一个(0,1)页面
    在这里插入图片描述


    改进型的时钟置换算法 最多需要进行四轮扫描


    3.2.4 页面分配策略

    1)页面分配、置换策略

    在这里插入图片描述
    固定分配全局置换
    为每个进程分配一定数量的物理块,整个进程运行期间都不变,若发生缺页,则只能 从该进程在内存中的页面中选出一页换出。

    可变分配局部置换最易于实现的物理块分配和置换策略
    缺页时,系统从空闲物理块队列中取出一个物理块分配给该进程可以动态增加进程的物理块。

    可变分配局部置换
    当某个进程发生缺页时,==只允许从该进程在内存中的页面选一页换出。==因此不会影响其他进程。若进程在运行中频繁缺页,系统再为进程分配若干物理块


    2)调入页面的时机

    预调页策略: 根据局部性原理(主要指空间局部性,即:如果当前访问了某个内存单元,在之后很有可能会接着访问与其相邻的那些内存单元。),一次调入若干个相邻的页面可能比一次调入一个页面更高效。但如果提前调入的页面中大多数都没被访问过,则又是低效的。因此可以预测不久之后可能访问到的页面,将它们预先调入内存,但目前预测 成功率只有50% 左右故这种策略主要用于进程的首次调入(运行前调入),由程序员指出应该先调入哪些部分。

    请求调页策略: 进程在运行期间发现缺页时才将所缺页面调入内存(运行时调入)。由这种策略调入的页面一定会被访问到,但由于每次只能调入一页,而每次调页都要磁盘I/0操作,因此I/0开销较大。


    3)从何处调入页面
    在这里插入图片描述
    对换区通常是采用连续分配方式,而文件区采用离散分配方式,故对换区的磁盘I/O速度比文件区的更快。
    1.系统拥有足够的对换区空间: 页面的调入、调出都是在内存与对换区之间进行,

    2.系统缺少足够的对换区空间: 凡是不会被修改的数据都直接从文件区调入,由于这些页面不会被修改,因此换出时不必写回磁盘,下次需要时再从文件区调入即可。对于可能被修改的部分,换出时需写回磁盘对换区,下次需要时再从对换区调入。

    3.UNIX方式:运行之前进程有关的数据全部放在文件区, 故未使用过的页面,都可从文件区调入。若被使用过的页面需要换出,则写回对换区,下次需要时从对换区调入。


    3.2.5 抖动

    刚刚换出的页面马上又要换入内存,刚刚换入的页面马上又要换出外存,这种频繁的页面调度行为称为抖动,或颠簸。产生抖动的主要原因是进程频繁访问的页面数目高于可用的物理块数(分配给进程的物理块不够)


    3.2.6 工作集

    驻留集: 指请求分页存储管理中给进程分配的内存块(页)的集合。
    工作集: 指在某段时间间隔里,进程实际访问页面的集合。

    工作集是指在某段时间间隔内,进程要访问的页面的集合。

    在这里插入图片描述
    驻留集大小不能小于工作集大小,否则进程运行过程中将频繁缺页。


    在这里插入图片描述

    例题
    在这里插入图片描述
    物理地址: 页框号+页内偏移
    逻辑地址: 逻辑号(页号)+页内偏移

    驻留集大小为2意味着只能有两个页存在于内存之中 页表中页号0、2在内存中,页号1不在,故需要页面置换算法淘汰 页面,注意是淘汰页号,不是页框号。

    在这里插入图片描述

    展开全文
  • 实验五 Windows XP 虚拟内存管理 一 实验目的 1) 了解存储器管理以及虚拟存储器管理的基本原理 2 了解和学习 Windows 系统管理工具中关于内存管理的设置和使用 二 实验环境 需要准备一台运行 Windows XP 操作系统的...
  • 操作系统对内存管理 没有内存抽象的年代 在早些的操作系统中,并没有引入内存抽象的概念。程序直接访问和操作的都是物理内存。比如当执行如下指令时:mov reg1,1000 这条指令会毫无想象力的将物理地址1000中的...

    操作系统对内存的管理

    没有内存抽象的年代

    在早些的操作系统中,并没有引入内存抽象的概念。程序直接访问和操作的都是物理内存。比如当执行如下指令时:mov reg1,1000

    这条指令会毫无想象力的将物理地址1000中的内容赋值给寄存器。不难想象,这种内存操作方式使得操作系统中存在多进程变得完全不可能,比如MS-DOS,你必须执行完一条指令后才能接着执行下一条。如果是多进程的话,由于直接操作物理内存地址,当一个进程给内存地址1000赋值后,另一个进程也同样给内存地址赋值,那么第二个进程对内存的赋值会覆盖第一个进程所赋的值,这回造成两条进程同时崩溃。

    没有内存抽象对于内存的管理通常非常简单,除去操作系统所用的内存之外,全部给用户程序使用。或是在内存中多留一片区域给驱动程序使用

    无内存抽象存在的问题

    1. 用户程序可以访问任意内存,容易破坏操作系统,造成崩溃

    2. 同时运行多个程序特别困难

    内存抽象:地址空间

    1. 基址寄存器与界限寄存器可以简单的动态重定位,每个内存地址送到内存之前,都会自动加上基址寄存器的内容。

    2. 交换技术把一个进程完全调入内存,使该进程运行一段时间,然后把它存回磁盘。空闲进程主要存在磁盘上,所以当他们不运行时就不会占用内存。

    为什么要有地址空间?

    首先直接把物理地址暴露给进程会带来严重问题

    1. 如果用户程序可以寻址内存的每个字节,就有很大的可能破坏操作系统,造成系统崩溃

    2. 同时运行多个程序十分困难 地址空间创造了一个新的内存抽象,地址空间是一个进程可用于寻址内存的一套地址的集合。每个进程都有一个自己的地址空间,并且这个地址空间独立于其它进程的地址空间。使用基址寄存器和界限器可以实现。

    虚拟内存

    虚拟内存是现代操作系统普遍使用的一种技术。前面所讲的抽象满足了多进程的要求,但很多情况下,现有内存无法满足仅仅一个大进程的内存要求(比如很多游戏,都是10G+的级别)。在早期的操作系统曾使用覆盖(overlays)来解决这个问题,将一个程序分为多个块,基本思想是先将块0加入内存,块0执行完后,将块1加入内存。依次往复,这个解决方案最大的问题是需要程序员去程序进行分块,这是一个费时费力让人痛苦不堪的过程。后来这个解决方案的修正版就是虚拟内存。

    虚拟内存的基本思想是,每个进程有用独立的逻辑地址空间,内存被分为大小相等的多个块,称为(Page).每个页都是一段连续的地址。对于进程来看,逻辑上貌似有很多内存空间,其中一部分对应物理内存上的一块(称为页框,通常页和页框大小相等),还有一些没加载在内存中的对应在硬盘上。

    由上图可以看出,虚拟内存实际上可以比物理内存大。当访问虚拟内存时,会通过MMU(内存管理单元)去匹配对应的物理地址,而如果虚拟内存的页并不存在于物理内存中,会产生缺页中断,从磁盘中取得缺的页放入内存,如果内存已满,还会根据某种算法将磁盘中的页换出。

    虚拟内存和物理内存的匹配是通过页表实现,页表存在MMU中,页表中每个项通常为32位,既4byte,除了存储虚拟地址和页框地址之外,还会存储一些标志位,比如是否缺页,是否修改过,写保护等。可以把MMU想象成一个接收虚拟地址项返回物理地址的方法。

    因为页表中每个条目是4字节,现在的32位操作系统虚拟地址空间会是2的32次方,即使每页分为4K,也需要2的20次方 * 4字节 = 4M的空间,为每个进程建立一个4M的页表并不明智。因此在页表的概念上进行推广,产生二级页表,二级页表每个对应4M的虚拟地址,而一级页表去索引这些二级页表,因此32位的系统需要1024个二级页表,虽然页表条目没有减少,但内存中可以仅仅存放需要使用的二级页表和一级页表,大大减少了内存的使用。

    引入多级页表的原因是避免把全部页表一直存在内存中

    虚拟地址和物理地址匹配规则

    虚拟页号可用做页表的索引,以找到该虚拟页面对应页表项。由页表项可以找到页框号。然后把页框号拼接到偏移量的高位端,以替换虚拟页号,形成送往内存的物理地址。

    页表的目的是把虚拟页面映射为页框,从数学的角度来说,页表是一个函数,它的参数是,虚拟页号,结果是物理页框号。通过这个函数可以把虚拟地址中的虚拟页面域替换为页框域,从而形成物理地址。

    页面置换算法

    地址映射过程中,若在页面中发现所要访问的页面不再内存中,则产生缺页中断。当发生缺页中断时操作系统必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。如果要换出的页面在内存驻留期间已经被修改过,就必须把它写回磁盘以更新该页面在磁盘的副本;如果该页面没有被修改过,那么它在磁盘上的副本已经是最新的,不需要回写。直接用调入的页面覆盖掉被淘汰的页面就可以了。而用来选择淘汰哪一页的规则叫做页面置换算法。

    因为在计算机系统中,读取少量数据硬盘通常需要几毫秒,而内存中仅仅需要几纳秒。一条CPU指令也通常是几纳秒,如果在执行CPU指令时,产生几次缺页中断,那性能可想而知,因此尽量减少从硬盘的读取无疑是大大的提升了性能。而前面知道,物理内存是极其有限的,当虚拟内存所求的页不在物理内存中时,将需要将物理内存中的页替换出去,选择哪些页替换出去就显得尤为重要,如果算法不好将未来需要使用的页替换出去,则以后使用时还需要替换进来,这无疑是降低效率的,让我们来看几种页面替换算法。

    最优页面置换算法(Optimal Page Replacement Algorithm)

    最饥饿页面置换算法是将未来最久不使用的页替换出去,这听起来很简单,但是无法实现。根据页面被访问前所需要的指令数作为标记,根据指令数的由多到少进行置换,这个方法对评价页面置换算法很有用,但它在实际系统中却不能使用,因为无法真正的实现。这种算法可以作为衡量其它算法的基准。

    最近最少使用页面置换算法(Least Recently Used)

    通常在前几条指令中使用频繁的页面很可能在后面几条指令中页频繁使用。LRU算法就是在缺页发生时首先置换最长时间未被使用的页面。优秀但是难以实现。

    最近未使用页面置换算法(Not Recently Used Replacement Algorithm)

    在最近的一个时钟周期内,淘汰一个没有被访问的已修改页面,近似 LRU 算法,NRU 只是更粗略些。

    这种算法给每个页一个标志位,R表示最近被访问过,M表示被修改过。定期对R进行清零。这个算法的思路是首先淘汰那些未被访问过R=0的页,其次是被访问过R=1,未被修改过M=0的页,最后是R=1,M=1的页。

    先进先出的页面置换算法(First-In First-Out Page Replacement Algorithm)

    这种算法的思想是淘汰在内存中最久的页,这种算法的性能接近于随机淘汰。可能抛弃重要的页面,并不好。

    第二次机会页面置换算法(Second Chance Page Replacement Algorithm)

    这种算法是在FIFO的基础上,为了避免置换出经常使用的页,增加一个标志位R,如果最近使用过将R置1,当页将会淘汰时,如果R为1,则不淘汰页,将R置0.而那些R=0的页将被淘汰时,直接淘汰。这种算法避免了经常被使用的页被淘汰。

    时钟替换算法(Clock Page Replacement Algorithm)

    虽然改进型FIFO算法避免置换出常用的页,但由于需要经常移动页,效率并不高。因此在改进型FIFO算法的基础上,将队列首位相连形成一个环路,当缺页中断产生时,从当前位置开始找R=0的页,而所经过的R=1的页被置0,并不需要移动页。

    下表是上面几种算法的简单比较:

    算法描述
    最佳置换算法无法实现,最为测试基准使用
    最近不常使用算法和LRU性能差不多
    先进先出算法有可能会置换出经常使用的页
    改进型先进先出算法和先进先出相比有很大提升
    最久未使用算法性能非常好,但实现起来比较困难
    时钟置换算法非常实用的算法

    分页系统中的设计问题

    1. 在任何分页式系统中,都需要考虑两个主要的问题:虚拟地址到到物理地址的映射必须非常快;如果虚拟地址空间很大,页表也会很大。

    2. 局部分分配策略与全局分配策略,怎样在相互竞争的可运行进程之间分配内存.

      • 局部分配为每个进程分配固定的内存片段,即使有大量的空闲页框存在,工作集的增长也会颠簸。

      • 全局分配在进程间动态地分配页框,分配给各个进程的页框数是动态变化的。给每个进程分配一个最小的页框数使无论多么小的进程都可以运行,再需要更大的内存时去公共的内存池里去取。

      • FIFO LRU 既适用于局部算法,也适用于全局算法。WSClock 工作集更适用于局部算法。

    3. 负载控制 , 即使使用了最优的页面置换算法,最理想的全局分配。当进程组合的工作集超出内存容量时,就可能发生颠簸。这时只能根据进程的特性(IO 密集 or CPU 密集)将进程交换到磁盘上。

    4. 页面大小 的确定不存在全局最优的结果,小页面减少页面内内存浪费,但是小页面,意味着更大的页表,更多的计算转换时间。现在一般的页面大小是 4KB 或 8KB

    5. 地址空间太小,所以分离指令空间,数据空间

    6. 共享页面,在数据空间和指令空间分离的基础上很容易实现程序的共享,linux 采取了 copy on write 的方案,也有数据的共享。

    7. 共享库,多个程序并发,如果有一个程序已经装在了共享库,其他程序就没有必要再进行装载,减少内存浪费。而且共享库并不会一次性的装入内存,而是根据需要以页面为单位进行装载的。共享时不使用绝对地址,使用相对偏移量的代码(位置无关代码 position-independent code)

    8. 共享库是内存映射文件的一种特例,核心思想是进程可以发起一个系统调用,将一个文件映射到其虚拟地址空间的一部分,在多数实现中在映射共享的页面时不会实际读入页面的内容,而是在访问时被每次一页的读入,磁盘文件被当作后背存储。当进程退出或显示的接触文件时,所有被改动的页面会被写入到文件中。

    9. 清除策略,发生缺页中断时有大量的空闲页框,此时的分页系统在最佳状态,有一个分页守护(paging daemon)的后台进程,它在多数时候睡眠,但会被定期唤醒,如果空闲页框过少,分页守护进程通过预定的页面置换算法选择页面换出内存。

    10. 虚拟内存接口,在一些高级系统中,程序员可以对内存映射进行控制,允许控制的原因是为了允许两个或多个进程共享一部分内存。页面共享可以用来实现高性能的消息传递系统。

    Linux内存管理

    内核空间

    页(page)是内核的内存管理的基本单位

    struct page {
     page_flags_t flags;  页标志符
     atomic_t _count;    页引用计数
     atomic_t _mapcount;     页映射计数
     unsigned long private;    私有数据指针
     struct address_space *mapping;    该页所在地址空间描述结构指针,用于内容为文件的页帧
     pgoff_t index;               该页描述结构在地址空间radix树page_tree中的对象索引号即页号
     struct list_head lru;        最近最久未使用struct slab结构指针链表头变量
     void *virtual;               页虚拟地址
    };
    
    • flags:页标志包含是不是脏的,是否被锁定等等,每一位单独表示一种状态,可同时表示出32种不同状态,定义在<linux/page-flags.h>

    • _count:计数值为-1表示未被使用。

    • virtual:页在虚拟内存中的地址,对于不能永久映射到内核空间的内存(比如高端内存),该值为NULL;需要事必须动态映射这些内存。

    尽管处理器的最小可寻址单位通常为字或字节,但内存管理单元(MMU,把虚拟地址转换为物理地址的硬件设备)通常以页为单位处理。内核用struct page结构体表示每个物理页,struct page结构体占40个字节,假定系统物理页大小为4KB,对于4GB物理内存,1M个页面,故所有的页面page结构体共占有内存大小为40MB,相对系统4G,这个代价并不高。

    内核把页划分在不同的区(zone)

    总共3个区,具体如下:

    描述物理内存(MB)
    ZONE_DMADMA使用的页<16
    ZONE_NORMAL可正常寻址的页16 ~896
    ZONE_HIGHMEM动态映射的页>896
    • 执行DMA操作的内存必须从ZONE_DMA区分配

    • 一般内存,既可从ZONE_DMA,也可从ZONE_NORMAL分配,但不能同时从两个区分配;

    用户空间

    用户空间中进程的内存,往往称为进程地址空间

    Linux采用虚拟内存技术。进程的内存空间只是虚拟内存(或者叫作逻辑内存),而程序的运行需要的是实实在在的内存,即物理内存(RAM)。在必要时,操作系统会将程序运行中申请的内存(虚拟内存)映射到RAM,让进程能够使用物理内存。

    地址空间

    每个进程都有一个32位或64位的地址空间,取决于体系结构。 一个进程的地址空间与另一个进程的地址空间即使有相同的内存地址,也彼此互不相干,对于这种共享地址空间的进程称之为线程。一个进程可寻址4GB的虚拟内存(32位地址空间中),但不是所有虚拟地址都有权访问。对于进程可访问的地址空间称为内存区域。每个内存区域都具有对相关进程的可读、可写、可执行属性等相关权限设置。

    内存区域可包含的对象:

    • 代码段(text section): 可执行文件代码

    • 数据段(data section): 可执行文件的已初始化全局变量(静态分配的变量和全局变量)。

    • bss段:程序中未初始化的全局变量,零页映射(页面的信息全部为0值)。

    • 进程用户空间栈的零页映射(进程的内核栈独立存在并由内核维护)

    • 每一个诸如C库或动态连接程序等共享库的代码段、数据段和bss也会被载入进程的地址空间

    • 任何内存映射文件

    • 任何共享内存段

    • 任何匿名的内存映射(比如由malloc()分配的内存)

    这些内存区域不能相互覆盖,每一个进程都有不同的内存片段。

    内存描述符

    内存描述符由mm_struct结构体表示

    struct mm_struct {
     struct vm_area_struct *mmap;
     rb_root_t mm_rb;
     ...
     atomic_t mm_users;
     atomic_t mm_count;
    ​
     struct list_head mmlist;
     ...
    };
    
    • mm_users:代表正在使用该地址的进程数目,当该值为0时mm_count也变为0;

    • mm_count: 代表mm_struct的主引用计数,当该值为0说明没有任何指向该mm_struct结构体的引用,结构体会被撤销。

    • mmap和mm_rb:描述的对象都是相同的

      • mmap以链表形式存放, 利于高效地遍历所有元素

      • mm_rb以红黑树形式存放,适合搜索指定元素

    • mmlist:所有的mm_struct结构体都通过mmlist连接在一个双向链表中,该链表的首元素是init_mm内存描述符,它代表init进程的地址空间。

    在进程的进程描述符(<linux/sched.h>中定义的task_struct结构体)中,mm域记录该进程使用的内存描述符。故current->mm代表当前进程的内存描述符。

    fork()函数 利用copy_mm函数复制父进程的内存描述符,子进程中的mm_struct结构体通过allcote_mm()从高速缓存中分配得到。通常,每个进程都有唯一的mm_struct结构体,即唯一的进程地址空间。

    当子进程与父进程是共享地址空间,可调用clone(),那么不再调用allcote_mm(),而是仅仅是将mm域指向父进程的mm,即 tsk->mm = current->mm。

    相反地,撤销内存是exit_mm()函数,该函数会进行常规的撤销工作,更新一些统计量。

    内核线程

    • 没有进程地址空间,即内核线程对应的进程描述符中mm=NULL

    • 内核线程直接使用前一个进程的内存描述符,仅仅使用地址空间中和内核内存相关的信息

    页表

    应用程序操作的对象时映射到物理内存之上的虚拟内存,而处理器直接操作的是物理内存。故应用程序访问一个虚拟地址时,需要将虚拟地址转换为物理地址,然后处理器才能解析地址访问请求,这个转换工作通过查询页表完成。

    Linux使用三级页表完成地址转换。

    1. 顶级页表:页全局目录(PGD),指向二级页目录;

    2. 二级页表:中间页目录(PMD),指向PTE中的表项;

    3. 最后一级:页表(PTE),指向物理页面。

    多数体系结构,搜索页表工作由硬件完成。每个进程都有自己的页表(线程会共享页表)。为了加快搜索,实现了翻译后缓冲器(TLB),作为将虚拟地址映射到物理地址的硬件缓存。还有写时拷贝方式共享页表,当fork()时,父子进程共享页表,只有当子进程或父进程试图修改特定页表项时,内核才创建该页表项的新拷贝,之后父子进程不再共享该页表项。可见,利用共享页表可以消除fork()操作中页表拷贝所带来的消耗。

    进程与内存

    所有进程都必须占用一定数量的内存,这些内存用来存放从磁盘载入的程序代码,或存放来自用户输入的数据等。内存可以提前静态分配和统一回收,也可以按需动态分配和回收。

    对于普通进程对应的内存空间包含5种不同的数据区:

    • 代码段

    • 数据段

    • BSS段

    • 堆:动态分配的内存段,大小不固定,可动态扩张(malloc等函数分配内存),或动态缩减(free等函数释放);

    • 栈:存放临时创建的局部变量;

    进程内存空间

    Linux采用虚拟内存管理技术,每个进程都有各自独立的进程地址空间(即4G的线性虚拟空间),无法直接访问物理内存。这样起到保护操作系统,并且让用户程序可使用比实际物理内存更大的地址空间。

    • 4G进程地址空间被划分两部分,内核空间和用户空间。用户空间从0到3G,内核空间从3G到4G;

    • 用户进程通常情况只能访问用户空间的虚拟地址,不能访问内核空间虚拟地址。只有用户进程进行系统调用(代表用户进程在内核态执行)等情况可访问到内核空间;

    • 用户空间对应进程,所以当进程切换,用户空间也会跟着变化;

    • 内核空间是由内核负责映射,不会跟着进程变化;内核空间地址有自己对应的页表,用户进程各自有不同额页表。

    内存分配

    进程分配内存,陷入内核态分别由brk和mmap完成,但这两种分配还没有分配真正的物理内存,真正分配在后面会讲。

    • brk: 数据段的最高地址指针_edata往高地址推

      • 当malloc需要分配的内存<M_MMAP_THRESHOLD(默认128k)时,采用brk;

      • brk分配的内存需高地址内存全部释放之后才会释放。(由于是通过推动指针方式)

      • 当最高地址空间的空闲内存大于M_TRIM_THRESHOLD时(默认128k),执行内存紧缩操作;

    • do_mmap:在堆栈中间的文件映射区域找空闲的虚拟内存

      • 当malloc需要分配的内存>M_MMAP_THRESHOLD(默认128k)时,采用do_map();

      • mmap分配的内存可以单独释放

    物理内存

    • 物理内存只有进程真正去访问虚拟地址,发生缺页中断时,才分配实际的物理页面,建立物理内存和虚拟内存的映射关系。

    • 应用程序操作的是虚拟内存;而处理器直接操作的却是物理内存。当应用程序访问虚拟地址,必须将虚拟地址转化为物理地址,处理器才能解析地址访问请求。

    • 物理内存是通过分页机制实现的

    • 物理页在系统中由也结构struct page描述,所有的page都存储在数组mem_map[]中,可通过该数组找到系统中的每一页。

    虚拟内存 转化为 真实物理内存:

    • 虚拟进程空间:通过查询进程页表,获取实际物理内存地址;

    • 虚拟内核空间:通过查询内核页表,获取实际物理内存地址;

    • 物理内存映射区:物理内存映射区与实际物理去偏移量仅PAGE_OFFSET,通过通过virt_to_phys()转化;

    虚拟内存与真实物理内存映射关系:

    其中物理地址空间中除了896M(ZONE_DMA + ZONE_NORMAL)的区域是绝对的物理连续,其他内存都不是物理内存连续。在虚拟内核地址空间中的安全保护区域的指针都是非法的,用于保证指针非法越界类的操作,vm_struct是连续的虚拟内核空间,对应的物理页面可以不连续,地址范围(3G + 896M + 8M) ~ 4G;另外在虚拟用户空间中 vm_area_struct同样也是一块连续的虚拟进程空间,地址空间范围0~3G。

    碎片问题

    • 外部碎片:未被分配的内存,由于太多零碎的不连续小内存,无法满足当前较大内存的申请要求;

      • 原因:频繁的分配与回收物理页导致大量的小块内存夹杂在已分配页面中间;

      • 解决方案:伙伴算法有所改善

    • 内部碎片:已经分配的内存,却不能被利用的内存空间;

      • 缘由:所有内存分配必须起始可被4、8或16(体系结构决定)整除的地址或者MMU分页机制限制;

      • 解决方案:slab分配器有所改善

      • 实例:请求一个11Byte的内存块,系统可能会分配12Byte、16Byte等稍大一些的字节,这些多余空间就产生碎片

    Android进程内存管理

    进程的地址空间

    在32位操作系统中,进程的地址空间为0到4GB,

    示意图如下:

    这里主要说明一下Stack和Heap:

    Stack空间(进栈和出栈)由操作系统控制,其中主要存储函数地址、函数参数、局部变量等等,所以Stack空间不需要很大,一般为几MB大小。

    Heap空间的使用由程序员控制,程序员可以使用malloc、new、free、delete等函数调用来操作这片地址空间。Heap为程序完成各种复杂任务提供内存空间,所以空间比较大,一般为几百MB到几GB。正是因为Heap空间由程序员管理,所以容易出现使用不当导致严重问题。

    进程内存空间和RAM之间的关系

    进程的内存空间只是虚拟内存(或者叫作逻辑内存),而程序的运行需要的是实实在在的内存,即物理内存(RAM)。在必要时,操作系统会将程序运行中申请的内存(虚拟内存)映射到RAM,让进程能够使用物理内存。

    RAM作为进程运行不可或缺的资源,对系统性能和稳定性有着决定性影响。另外,RAM的一部分被操作系统留作他用,比如显存等等,内存映射和显存等都是由操作系统控制,我们也不必过多地关注它,进程所操作的空间都是虚拟地址空间,无法直接操作RAM。

    示意图如下:

    Android中的进程

    Native进程:采用C/C++实现,不包含Dalvik实例的Linux进程,/system/bin/目录下面的程序文件运行后都是以native进程形式存在的。上图 /system/bin/surfaceflinger、/system/bin/rild、procrank等就是Native进程。

    Java进程:实例化了Dalvik虚拟机实例的Linux进程,进程的入口main函数为Java函数。Dalvik虚拟机实例的宿主进程是fork()系统调用创建的Linux进程,所以每一个Android上的Java进程实际上就是一个Linux进程,只是进程中多了一个Dalvik虚拟机实例。因此,Java进程的内存分配比Native进程复杂。下图,Android系统中的应用程序基本都是Java进程,如桌面、电话、联系人、状态栏等等。

    Android中进程的堆内存

    进程空间中的Heap空间是我们需要重点关注的。Heap空间完全由程序员控制,我们使用的C Malloc、C++ new和Java new所申请的空间都是Heap空间, C/C++申请的内存空间在Native Heap中,而Java申请的内存空间则在Dalvik Heap中。

    Android的 Java程序为什么容易出现OOM

    这个是因为Android系统对Dalvik的VM Heapsize作了硬性限制,当java进程申请的Java空间超过阈值时,就会抛出OOM异常(这个阈值可以是48M、24M、16M等,视机型而定),可以通过adb shell getprop | grep dalvik.vm.heapgrowthlimit查看此值。

    也就是说,程序发生OMM并不表示RAM不足,而是因为程序申请的Java Heap对象超过了Dalvik VM Heap Growth Limit。也就是说,在RAM充足的情况下,也可能发生OOM。

    这样的设计似乎有些不合理,但是Google为什么这样做呢?这样设计的目的是为了让Android系统能同时让比较多的进程常驻内存,这样程序启动时就不用每次都重新加载到内存,能够给用户更快的响应。迫使每个应用程序使用较小的内存,移动设备非常有限的RAM就能使比较多的App常驻其中。但是有一些大型应用程序是无法忍受VM Heap Growth Limit的限制的。

    Android如何应对RAM不足

    Java程序发生OMM并不是表示RAM不足,如果RAM真的不足,会发生什么呢?这时Android的Memory Killer会起作用,当RAM所剩不多时,Memory Killer会杀死一些优先级比较低的进程来释放物理内存,让高优先级程序得到更多的内存。

    应用程序如何绕过DalvikVM Heap Size的限制

    对于一些大型的应用程序(比如游戏),内存使用会比较多,很容易超超出VM Heapsize的限制,这时怎么保证程序不会因为OOM而崩溃呢?

    创建子进程

    创建一个新的进程,那么我们就可以把一些对象分配到新进程的Heap上了,从而达到一个应用程序使用更多的内存的目的,当然,创建子进程会增加系统开销,而且并不是所有应用程序都适合这样做,视需求而定。

    创建子进程的方法:使用android:process标签

    使用JNI在Native Heap上申请空间(推荐使用)

    Native Heap的增长并不受Dalvik VM heapsize的限制,它的Native Heap Size已经远远超过了Dalvik Heap Size的限制。

    只要RAM有剩余空间,程序员可以一直在Native Heap上申请空间,当然如果RAM快耗尽,Memory Killer会杀进程释放RAM。大家使用一些软件时,有时候会闪退,就可能是软件在Native层申请了比较多的内存导致的。比如,我就碰到过UC Web在浏览内容比较多的网页时闪退,原因就是其Native Heap增长到比较大的值,占用了大量的RAM,被Memory Killer杀掉了。

    使用显存(操作系统预留RAM的一部分作为显存)

    使用OpenGL Textures等API,Texture Memory不受Dalvik VM Heapsize限制。再比如Android中的GraphicBufferAllocator申请的内存就是显存。

    Bitmap分配在Native Heap还是Dalvik Heap上?

    一种流行的观点是这样的:

    Bitmap是JNI层创建的,所以它应该是分配到Native Heap上,并且为了解释Bitmap容易导致OOM,提出了这样的观点:native heap size + dalvik heapsize <= dalvik vm heapsize。但是Native Heap Size远远超过Dalvik VM Heap Size,所以,事实证明以上观点是不正确的。

    正确的观点:

    大家都知道,过多地创建Bitmap会导致OOM异常,且Native Heap Size不受Dalvik限制,所以可以得出结论:

    Bitmap只能是分配在Dalvik Heap上的,因为只有这样才能解释Bitmap容易导致OOM。

    Android内存管理机制

    从操作系统的角度来说,内存就是一块数据存储区域,是可被操作系统调度的资源。在多任务(进程)的OS中,内存管理尤为重要,OS需要为每一个进程合理的分配内存资源。所以可以从OS对内存和回收两方面来理解内存管理机制。

    • 分配机制:为每一个任务(进程)分配一个合理大小的内存块,保证每一个进程能够正常的运行,同时确保进程不会占用太多的内存。
    • 回收机制:当系统内存不足的时候,需要有一个合理的回收再分配机制,以保证新的进程可以正常运行。回收时杀死那些正在占用内存的进程,OS需要提供一个合理的杀死进程机制。

    同样作为一个多任务的操作系统,Android系统对内存管理有有一套自己的方法,手机上的内存资源比PC更少,需要更加谨慎的管理内存。理解Android的内存分配机制有助于我们写出更高效的代码,提高应用的性能。

    下面分别从**分配 回收 **两方面来描述Android的内存管理机制:

    分配机制

    Android为每个进程分配内存时,采用弹性的分配方式,即刚开始并不会给应用分配很多的内存,而是给每一个进程分配一个“够用”的内存大小。这个大小值是根据每一个设备的实际的物理内存大小来决定的。随着应用的运行和使用,Android会为进程分配一些额外的内存大小。但是分配的大小是有限度的,系统不可能为每一个应用分配无限大小的内存。

    总之,Android系统需要最大限度的让更多的进程存活在内存中,以保证用户再次打开应用时减少应用的启动时间,提高用户体验。

    回收机制

    Android对内存的使用方式是“尽最大限度的使用”,只有当内存水足的时候,才会杀死其它进程来回收足够的内存。但Android系统否可能随便的杀死一个进程,它也有一个机制杀死进程来回收内存。

    Android杀死进程有两个参考条件:

    1. 回收收益

    当Android系统开始杀死LRU缓存中的进程时,系统会判断每个进程杀死后带来的回收收益。因为Android总是倾向于杀死一个能回收更多内存的进程,从而可以杀死更少的进程,来获取更多的内存。杀死的进程越少,对用户体验的影响就越小。

    2. 进程优先级

    下面将从 Application Framework 和 Linux kernel 两个层次分析 Android 操作系统的资源管理机制。

    Android 之所以采用特殊的资源管理机制,原因在于其设计之初就是面向移动终端,所有可用的内存仅限于系统 RAM,必须针对这种限制设计相应的优化方案。当 Android 应用程序退出时,并不清理其所占用的内存,Linux 内核进程也相应的继续存在,所谓“退出但不关闭”。从而使得用户调用程序时能够在第一时间得到响应。当系统内存不足时,系统将激活内存回收过程。为了不因内存回收影响用户体验(如杀死当前的活动进程),Android 基于进程中运行的组件及其状态规定了默认的五个回收优先级:

    Android为每一个进程分配了优先组的概念,优先组越低的进程,被杀死的概率就越大。根据进程的重要性,划分为5级:

    1)前台进程(Foreground process)

    用户当前操作所必需的进程。通常在任意给定时间前台进程都为数不多。只有在内存不足以支持它们同时继续运行这一万不得已的情况下,系统才会终止它们。

    2)可见进程(Visible process)

    没有任何前台组件、但仍会影响用户在屏幕上所见内容的进程。可见进程被视为是极其重要的进程,除非为了维持所有前台进程同时运行而必须终止,否则系统不会终止这些进程。

    3)服务进程(Service process)

    尽管服务进程与用户所见内容没有直接关联,但是它们通常在执行一些用户关心的操作(例如,在后台播放音乐或从网络下载数据)。因此,除非内存不足以维持所有前台进程和可见进程同时运行,否则系统会让服务进程保持运行状态。

    4)后台进程(Background process)

    后台进程对用户体验没有直接影响,系统可能随时终止它们,以回收内存供前台进程、可见进程或服务进程使用。 通常会有很多后台进程在运行,因此它们会保存在 LRU 列表中,以确保包含用户最近查看的 Activity 的进程最后一个被终止。如果某个 Activity 正确实现了生命周期方法,并保存了其当前状态,则终止其进程不会对用户体验产生明显影响,因为当用户导航回该 Activity 时,Activity 会恢复其所有可见状态。

    5)空进程(Empty process)

    不含任何活动应用组件的进程。保留这种进程的的唯一目的是用作缓存,以缩短下次在其中运行组件所需的启动时间。 为使总体系统资源在进程缓存和底层内核缓存之间保持平衡,系统往往会终止这些进程。

    通常,前面三种进程不会被杀死。

    ActivityManagerService 集中管理所有进程的内存资源分配。所有进程需要申请或释放内存之前必须调用 ActivityManagerService 对象,获得其“许可”之后才能进行下一步操作,或者 ActivityManagerService 将直接“代劳”。ActivityManagerService类中涉及到内存回收的几个重要的成员方法如下:trimApplications()、updateOomAdjLocked()、activityIdleInternal() 。这几个成员方法主要负责 Android 默认的内存回收机制,若 Linux 内核中的内存回收机制没有被禁用,则跳过默认回收。

    默认回收过程

    Android 操作系统中的内存回收可分为两个层次,即默认内存回收与Linux内核级内存回收,所有代码可参见 ActivityManagerService.java。

    回收动作入口:activityIdleInternal()

    Android 系统中内存回收的触发点大致可分为三种情况。第一,用户程序调用 StartActivity(), 使当前活动的 Activity 被覆盖;第二,用户按 back 键,退出当前应用程序;第三,启动一个新的应用程序。这些能够触发内存回收的事件最终调用的函数接口就是 activityIdleInternal()。当 ActivityManagerService 接收到异步消息 IDLE_TIMEOUT_MSG 或者 IDLE_NOW_MSG 时,activityIdleInternal() 将会被调用。



    作者:Mr槑
    链接:https://www.jianshu.com/p/2b11639905ec
    来源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

    展开全文
  • 内存管理:页式虚拟内存管理

    千次阅读 2019-12-17 21:00:38
    页式存储管理——虚拟内存——缺页中断,页面替换算法 开章明意: 创建一个进程(创建进程是在磁盘中),进程以字节为单位编号,然后再进程分为许多页(每页4KB),内存中有对应的页框(设定同页)。通过页表(记录...

    页式存储管理——虚拟内存——缺页中断,页面替换算法

    开章明意: 创建一个进程(创建进程是在磁盘中),进程以字节为单位编号,然后再进程分为许多页(每页4KB),内存中有对应的页框(设定同页)。通过页表(记录页和页框的对应关系),将最需要的页调入内存,其他页留在磁盘中。根据CPU的需要动态的更新页表,并调入调出页,实现对内存的充分利用。
    本质就是:内存局部读入进程,其余的存储在磁盘中


    内存不够用的问题—— 现阶段通常使用8G内存,但一个大型游戏就要10G+内存,如何解决?
    虚拟内存:给每个进程分配一个独立的地址空间(本质在磁盘上),每个进程独立的地址空间就叫虚拟内存。 虚拟内存中的页是连续的,但可以对应到内存中不连续的页框,这样就实现了对内存的充分利用。(不要求内存提供连续的存储空间)
    在这里插入图片描述
    当进程建立时, 数据储存于磁盘内的虚拟内存空间,也不需要为该进程去配置主内存空间,只有当该进程的页被调用的时候才会被加载到实际内存中。
    在这里插入图片描述
    操作系统为了管理内存,给每个进程都分配独立的地址空间,对32位的系统而言,这个空间的大小是4GB。这4GB并不是实际的物理内存,实际上并不存在,因此有虚拟内存这一名称。

    建立映射关系: 页(page),页框(frame),页表
    分为大小相等的多个块,称为页(Page).每个页都是虚拟内存中一段连续的地址(一般一页为4Kb),其中一部分对应物理内存上的一块(称为页框,通常页和页框大小相等),还有一些没加载在内存中的对应在硬盘上。
    内存构成: 8G, 按字节为单位编号(0-许多,这些编号就叫做地址),再按页框(一般为4KB)为单位进行与磁盘的数据交换.

    页表结构: ——页表完成虚拟地址到物理内存地址的映射,每个进程都有一个自己的页表,
    在这里插入图片描述
    页表的每一项的属性
    1.页号——页框号
    2.偏移量:内存的基地址加上偏移量找到想要的内存地址 即地址空间计算时的公式
    3.存在位:页是否在内存中
    页表中每个项通常为32位,既4byte,除了存储虚拟地址和页框地址之外,还会存储一些标志位,比如是否缺页,是否修改过,写保护等。

    页表存在MMU(memory management unit 内存管理部件)中
    在这里插入图片描述

    缺页中断,页面置换
    进程线性地址空间里的页面不必常驻内存,在执行一条指令时,如果发现要访问的虚拟内存的页并不存在于物理内存中(存在位为0),那么停止该指令的执行,并产生一个页不存在异常,故障处理程序从磁盘中取得缺的页放入内存,如果内存已满按页面置换算法来废弃某个页面,将其所占据的物理页释放出来,再调入所需页。

    页面置换算法:决定将哪些页面替换出去
    选择哪些页替换出去就显得尤为重要,如果算法不好将未来需要使用的页替换出去,则以后使用时还需要替换进来,这无疑是降低效率的。

    1.最佳置换算法(Optimal Page Replacement Algorithm)
    将未来最久不使用的页替换出去,这听起来很简单,但是无法实现。但是这种算法可以作为衡量其它算法的基准
    2.时钟替换算法: 最常用的算法
    3.先进先出算法:淘汰在内存中最久的页,这种算法的性能接近于随机淘汰。并不好
    4.最近不常使用算法: 淘汰最不经常访问的页项

    空闲内存管理
    系统要用什么样的数据结构记录内存的使用情况? ——
    空闲区链表
    用一个表来记录内存中空闲的页框
    在这里插入图片描述
    当很多个空闲分区都能满足进程的内存需求时,应该选择哪个分区进行分配? —动态内存分配算法
    1.最先匹配(First Fit Allocation):足够大的第一个空闲区 最简单 不用搜索整个表
    在这里插入图片描述
    2.最佳匹配算法(Best fit): 搜索整个空闲区表,找到符合要求的最小空闲区 应用最广泛
    在这里插入图片描述
    3.最差匹配算法(Worst fit): 搜索整个表,分配最大的可用空间,性能最差
    在这里插入图片描述


    内存管理机制完善(三项实际中使用的技术)
    对核心的页式虚拟内存管理的完善: ** 两级页表机制 + 页面高速缓存技术 + 段页式存储管理**
    1.段页式存储管理(实际使用的管理方式): 页式存储管理能有效地提高内存利用率,而分段存储管理能反映程序的逻辑结构并有利于段的共享。如果将这两种存储管理方法结合起来,就形成了段页式存储管理方式。段页式管理就是将程序分为多个逻辑段,在每个段里面又进行分页,即将分段和分页组合起来使用。
    2…两级页表:二级页表 页目录—页表 二级结构,节省内存
    3…页面高速缓存技术:又称为快表,提供中间由虚拟地址转换为物理地址时的缓存(缓存思想,缓存最常用的页),可以直接将虚拟地址映射到物理地址,加速分页过程
    在这里插入图片描述


    其他的一些基本概念:
    1.重叠overlay ——即段式管理
    如果一个程序需要使用比物理内存更大的内存空间怎么办?
    此时,可以将程序按照功能分成一段一段功能相对完整的单元,一个单元执行完成后再执行下一个单元,这就是重叠(overlay)
    2.交换技术:在磁盘中创建交换区,把一个最需要处理的进程完全调入内存(进程调度算法),使该进程运行一段时间。内存中进程未处于运行态时,就调出内存到磁盘交换区(即挂起),再调另一个完整进程进内存。空闲进程主要存在磁盘上,所以当他们不运行时就不会占用内存
    3.动态重定位:基址寄存器,界限寄存器
    基址寄存器: 寄存程序的起始物理地址
    界限寄存器: 寄存程序的长度
    在这里插入图片描述
    为什么不能直接使用物理地址:
    1.内存不够直接运行大型程序:内存往往是不够用的: 建立认知—— 计算机开机会启动大约100个进程,每个大约5-10M,
    工作中的PS应用程序占 1G 左右内存 一个大型游戏就是10G+内存需求
    2.无法并发:并发的概念——举例理解: 多个程序保持就绪态,随时可以运行
    在这里插入图片描述
    不同程序使用内存中不同的地址块 —— 使用绝对物理地址: 导致对内存地址的不正确访问(因为两个程序都使用绝对物理地址,两个程序访问地址冲突导致程序崩溃)
    3. 在简单嵌入式系统中可以直接引用物理地址
    在这里插入图片描述
    内存管理直观—— 进程管理器: ctrl + Alt + delete
    在这里插入图片描述

    展开全文
  • 计算机操作系统虚拟内存管理

    千次阅读 2018-07-30 14:29:12
    上一节所讨论的各种内存管理策略都是为了同时将多个进程保存在内存中以便允许多道程序设计。它们都具有以下两个共同的特征: 1) 一次性 作业必须一次性全部装入内存后,方能开始运行。这会导致两种情况发生: 当...
  • 虚拟内存技术的实现

    千次阅读 2020-09-21 21:37:54
    虚拟内存技术的实现需要建立在离散分配的内存管理方式的基础上。虚拟内存的实现有以下三种方式: 1. 请求分页存储管理:建立在分页管理之上,为了支持虚拟存储器功能而增加了请求调页功能和页面置换功能。请求分页...
  • 文章目录一、虚拟内存二、虚拟内存的作用三、分页系统实现虚拟内存原理1、虚拟内存技术的实现2、请求分页管理方式 一、虚拟内存   虚拟内存的基本思想是:每个程序拥有自己的地址空间,这个空间被分割成多个块,...
  • 虚拟内存技术

    千次阅读 2018-05-23 16:56:55
    虚拟内存技术允许执行进程不必完全的在内存当中,这种方案的显著的优点就是程序可以比物理内存大,虚拟内存其实就是把内存抽象成了一个巨大的、统一的存储数组,进而会将用户所看到的逻辑内存与物理内存分开 ...
  • 虚拟内存原理

    千次阅读 2019-10-05 10:36:58
    虚拟内存:为了更加高效并且少出错,现代操作系统提供了一种对主存的抽象概念,叫做虚拟内存虚拟内存是硬件异常,硬件地址翻译,主存,磁盘文件和内核软件的完美交互,他为每个进程提供了一个大的,一致和私有的...
  • 今天 我们主要为各位朋友们讲解内存分页管理、虚拟内存介绍。传统存储管理方式的特征 上一节所讨论的各种内存管理策略都是为了同时将多个进程保存在内存中以便允许多道程序设计。它们都具有以下两个共同的特征:  ...
  • 一、虚拟内存术语  虚拟内存   在存储分配机制中,尽管备用地址是主内存的一部分,它也可以被寻址。程序引用内存使用的地址与内存系统用于识别的物理地址是不同的,程序生成的地址会自动转化为...
  • 什么是虚拟内存

    万次阅读 多人点赞 2019-11-09 15:33:02
    虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行...
  • 文章目录1.1 虚拟存储器的定义1.2 虚拟存储器的特征1.3 虚拟内存技术的实现1.4 请求分页管理方式1.4.1 页表机制1.4.2 缺页中断机构1.4.3 地址变换机构1.5 页面置换算法1.6 页面分配策略1.6.1 驻留集大小1.6.2 调入...
  • 页式段式等各种内存管理策略是为了将多个进程保存在内存中以便允许多道程序设计,它们都具有以下两个共同的特征: 一次性: 作业必须一次性全部被装入内存后,方能开始运行。 (1)当作业很大时,将使该作业无法...
  • 在科技与互联网快速发展的...但是如果是早些购买的电脑,电脑内训一般是2G,日常使用出现运行缓慢时,我们会设置虚拟内存来解决,“虚拟内存”大多小伙伴都听过,但是这个有什么用呢?我们该如何设置?1、虚拟内存的...
  • 【Linux】Linux的虚拟内存详解(MMU、页表结构)

    万次阅读 多人点赞 2018-07-16 20:16:28
    为解决这个问题,人们设计了许多的方案,其中最成功的当属虚拟内存技术。Linux作为一个以通用为目的的现代大型操作系统,当然也毫不例外的采用了优点甚多的虚拟内存技术。   虚拟内存 为了运行比实际物理内存...
  • 虚拟内存以及进程的虚拟内存分布(第六章)

    千次阅读 多人点赞 2019-05-17 10:59:58
    在现代计算机操作系统中,计算机同时运行多个程序,为了提高CPU的利用率和物理内存的利用率,操作系统应用虚拟内存机制来管理内存。 本文介绍一些与虚拟内存相关的概念。 目录 1.物理内存 vs 虚拟内存 2.物理...
  • 虚拟内存的意义及管理

    千次阅读 2017-08-31 14:44:48
    虚拟内存的意义及管理总结—虚拟内存有以下几个作用: 1. 内存访问保护 2. 按需分页(lazy load技术) 3. 页换入换出(page swap in/out) 4. 写时复制(copy on write) 什么是虚拟内存?简单地说,是指...
  • 虚拟内存技术的实现是建立在离散分配的内存管理的基础上的 目前最常用的三种实现虚拟内存技术的方法: 请求分页存储管理 请求分段存储管理 请求段页式存储管理 以上三种方式,无论哪种,都需要以下三个条件: ...
  • 虚拟内存、物理内存/RAM 干嘛的

    千次阅读 2021-07-21 10:17:57
    本文记录自己理解后的虚拟内存、物理内存的作用前言虚拟内存 前言 了解之前先了解几个概念 1>RAM 随机存储器: 也就是我们经常说的内存条:同事跟我说,他电脑内存8个G,想玩吃鸡。 我回答他:你才8个G,玩不了,...
  • 虚拟内存对于很多电脑用户都不会陌生,尤其是曾经的一些老电脑,我们经常会通过合理设置电脑虚拟内存,来提升电脑运行速度。那么 Win10虚拟内存怎么设置最好,设置多少最合适呢?针对这个问题,今天小编就来给大伙...
  • 物理内存与虚拟内存之间的映射

    千次阅读 2017-11-17 14:41:55
    2、虚拟存储器的容量限制:主存容量+辅存(硬盘)容量。 3、物理内存:在应用中,真实存在的,插在主板内存槽上的内存条的容量的大小。从本质上来说,物理内存是代码和数据在其中运行的窗口。 4、
  • Linux操作系统采用虚拟内存管理技术,使得每个进程都有各自互不干涉的进程地址空间。该空间是块大小为4G的线性虚拟空间,用户所看到和接触到的都是该虚拟地址,无法看到实际的物理内存地址。利用这种虚拟地址不但能...
  • 深入理解内存(3):内存交换技术,虚拟内存 2013-01-15 21:14 1560人阅读 评论(0) 收藏 举报 分类: 3) C++(59) 1)IT Related(21) 版权声明:本文为博主原创文章,未经博主允许...
  • 利用虚拟内存技术,索引技术实现了对超长学生档案系统的管理
  • Linux虚拟内存和缺页中断

    千次阅读 多人点赞 2020-08-02 21:46:06
    虚拟内存技术使得不同进程在运行过程中,它所看到的是自己独自占有了当前系统的4G内存。所有进程共享同一物理内存,每个进程只把自己目前需要的虚拟内存空间映射并存储到物理内存上。 事实上,在每个进程创建加载时...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 190,985
精华内容 76,394
关键字:

虚拟内存管理技术