OS之内存管理 ---基本的内存管理策略(一)
基本概念
基本硬件
CPU可以直接访问的通用存储只有内存和处理器的内置的寄存器。机器指令可以用内存地址作为参数,而不能用磁盘地址作为参数。所以执行指令以及指令使用的数据,应在这些可执行访问的存储设备上,如果数据不在内存中,那么在CPU使用他们之前应把数据移到内存上。
CPU内置寄存器通常可以在一个CPU时钟周期内完成访问,但是对于内存,完成内存的访问可能需要多个CPU时钟周期,这种结果造成的影响就是如果没有数据用于完成正在执行的指令,那么CPU可能将会多次中断(暂停)。所以需要在CPU和内存之间增加一个高速缓存。
为了确保进程的执行正确,需要为每个进程分配一块单独的内存空间,从而使进程内存空间保护进程而互相不受到影响。通过两个寄存器,通常为基地址寄存器和界限地址寄存器。基地址寄存器中含有最小的合法的物理内存大小;界限地址寄存器中指定了进程范围的大小。内存空间的保护实现是通过在CPU硬件对在用户模式下产生的地址和寄存器的地址进行比较来完成的。也只有操作系统可以通过特殊的特权指令,才能加载基地址寄存器和界限地址寄存器,因为特权指令只能在内核模式下执行,所以只有操作系统可以加载基地址寄存器和界限地址寄存器。
地址绑定
通常程序是作为二进制可执行文件存放在磁盘上的,如果需要执行的话,首先要将程序调入内存并放在进程中。在磁盘上等待调入内存以便执行的进程形成了输入队列。
大多数情况下,用户程序在执行前,需要经过好几个步骤,在这些步骤中,地址可能会有不同的表示形式。源程序中地址通常使用符号表示,编译器通常将这些符号地址绑定到可重定位的地址。链接程序或加载程序在将这些可重定位的地址绑定到绝对地址。每次绑定都是从一个地址空间到另一个地址空间的映射。
通常,指令和数据绑定到存储器地址可在沿途的任何一步中进行:
- 编译时:如果编译时就已经知道进程将在内存中的驻留地址,那么就可以生成绝对代码,如果将来开始地址发生变化,那么就有必要重新编译代码。
- 加载时:如果在编译时不知道进程将驻留在何处,那么编译器就应生成可重定位代码。对这种情况,最后绑定会延迟到加载时才进行。如果开始地址发生变化,那么只需要重新加载用户代码以合并更改的值。
- 执行时:如果进程在执行时可以从一个内存段移到另一个内存段,那么绑定应延迟到执行时才进行。大多数通用操作系统就是采用这种方式的。
逻辑地址空间和物理地址空间
CPU生成的地址通常称为逻辑地址,而内存单元看到的地址(即加载到内存地址寄存器的地址)通常是物理地址。编译时和加载时的地址绑定方法生成相同的逻辑地址和物理地址,但是执行时的地址绑定方案生成不同的逻辑地址和物理地址。在这种情况下,通常成逻辑地址为虚拟地址。
从虚拟地址到物理地址的运行时映射是由**内存管理单元(MMU)**的硬件设备来完成。用户进程所生成的地址在送交到内存之前,都将加上重定位寄存器的值(基地址寄存器)。而用户程序不会看到真实的物理地址。
动态加载
在之前的进程加载到内存中,是将进程的整个程序和所有数据都加载到物理内存当中,所以进程的大小受限于内存的大小,为了获得内存空间利用率,可以采用动态加载。采用动态加载时,一个程序只有在调用时才会加载,所有程序都以可重定位加载格式保存在磁盘中。主程序被加载到内存并执行,当一个程序需要调用另一个程序时,调用程序首先检查另外一个程序是否已经加载到内存中。如果没有,可重定位链接程序会加载所需的程序到内存中,并更新程序的地址表以反映这个变化,接着控制传递给新加载的程序。所以,动态加载的好处就是,只有一个程序需要时才会被加载。
动态链接
动态链接库是系统库,可链接到用户程序,以便运行。
如果是静态链接的话,它的系统库与其他目标模块一样,通过加载程序被合并到二进制程序映像。但是动态链接库类似动态加载(注意在这里不是加载而是链接),会延迟到运行时。
如果有动态链接,在二进制映像中,每个库程序的引用都有一个存根。存根是一小段代码,用来支出如何定位适当的内存驻留库程序,或者在程序不在内存时应如何加载库。当执行存根时,他首先检查所需程序是否已经在内存中,如果不在,将程序加到内存中。存根会用程序地址来代替自己,并开始执行程序,所以下次在执行程序代码的时候,就可以直接进行,而不会因动态链接产生任何开销。
进程交换
进程必须在内存中以便执行,但是,进程可以短暂的从内存交换到备份存储,当再次执行时在调回到内存中。
标准交换
标准交换在内存和备份存储之间移动进程,备份存储通常是快速磁盘。备份存储应该足够的大,以容纳所有用户的所有内存映像的副本,并且应提供对这些存储器映像的直接访问。系统维护一个可运行的所有进程的就绪队列,他们的映像在备份存储和内存中,当CPU调度器决定要执行一个进程时,它调用分派器。分派器检查队列中的下一个进程是否在内存中,如果不在且没有空闲内存区域,那么分派器会换出当前位于内存的一个进程并换入所需进程,然后重新加载寄存器,并将控制权给所选进程。
移动系统的交换
移动系统通常不支持任何形式的交换,移动设备通常采用闪存,而不是空间更大的硬盘作为他的永久存储。苹果的IOS和谷歌的Android的具体交换策略可以自行百度。
连续内存分配
连续内存分配是早期OS所采用的一种内存分配策略,在采用连续内存分配时每个进程位于一个连续的内存区域,与包含下一个进程的内存相连。
内存保护
为了放置进程访问不属于他们的内存,依旧通过重定位寄存器和界限寄存器来实现保护,MMU通过动态的将逻辑地址加上重定位寄存器的值。当CPU调度器选择一个进程来执行时,作为上下文切换工作的一部分,分派器会用正确的值来加载重定位寄存器和界限寄存器。由于CPU所产生的每个地址都需要与这些寄存器进行核对,所以可以保证操作系统和其他用户的程序和数据不受该运行进程的影响。
内存分配
最简单的内存分配方法,就是将内存分为多个固定大小的分区。每个分区可以只包含一个进程。所以多道程序的程度受限于分区数。
对于可变分区方法,操作系统维护一张表,用于记录哪些内存可用和哪些内存已用。开始时所有内存都可用于用户进程,因此可以作为一大块的可用内存,称为孔。最后内存有一个集合,以包含各种大小的孔。
通常可用的内存块为分散在内存里的不同大小的孔的集合。当新进程需要内存时,系统为该进程查找足够大的孔。如果孔太大,那么就分为两块:一块分给进程,一块返回孔集合。这种方法是通用动态存储分配问题的一个例子。从一组可用孔中选择一个空闲孔的最常用方法有:
- 首次适应:分配首个足够大的孔,查找可以从头开始,也可以从上次首次适应结束时开始。一旦找到足够大的空闲孔,就可以停止.
- 最优适应:分配最小的足够大的孔。应查找整个列表,除非列表按大小排序。这种方法可以产生最小剩余孔
- 最差适应:分配最大的孔。同样应该查找整个列表,除非列表按大小排序这种方法可以产生最大剩余孔。
碎片
用于内存分配的首次适应和最优适应算法都会有外部碎片。对于内存的碎片可以是内部碎片,也可以是外部的。比如假设有一个18464字节大小的孔,有一个进程需要18462字节,如果只能分配所要求的块,那么还剩下2字节的孔。因此通常按固定大小的块为单位来分配内存,采用这种方法,进程所分配的内存可能比所需要的大,这两个数字之差称为内部碎片,这部分内存存在于分区内部,但是又不能用。
外部碎片的一种解决方法是紧缩,移动内存内容,以便将所有的空闲空间合并成一整块。但是紧缩并不是总是可能的。如果重定位是静态的,并且在汇编时或加载时进行的,那么就不能紧缩;只有重定位是动态的,且在运行时进行的,那么才可以采用紧缩。
OS之内存管理 ---基本的内存管理策略(一)的更多相关文章
- 【uTenux实验】内存池管理(固定内存池和可变内存池)
1.固定内存池管理实验 内存管理是操作系统的一个基础功能.uTenux的内存池管理函数提供了基于软件的内存池管理和内存块分配管理.uTenux的内存池有固定大小的内存池和大小可变的内存池之分,它们被看 ...
- 转:内存区划分、内存分配、常量存储区、堆、栈、自由存储区、全局区[C++][内存管理][转载]
内存区划分.内存分配.常量存储区.堆.栈.自由存储区.全局区[C++][内存管理][转载] 一. 在c中分为这几个存储区1.栈 - 由编译器自动分配释放2.堆 - 一般由程序员分配释放,若程序员不释放 ...
- (转)从内存管 理、内存泄漏、内存回收探讨C++内存管理
http://www.cr173.com/html/18898_all.html 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟 ...
- 5. c++ 内存管理 C/C++ 内存机制
参考自:http://blog.csdn.net/wpf_ml/article/details/7759911 1. 内存,Cache,寄存器内存:通常计算机将数据存放在物理内存,cache及寄存器中 ...
- Java内存管理:Java内存区域 JVM运行时数据区
转自:https://blog.csdn.net/tjiyu/article/details/53915869 下面我们详细了解Java内存区域:先说明JVM规范定义的JVM运行时分配的数据区有哪些, ...
- Linux-内存管理机制、内存监控、buffer/cache异同
在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是Linux内存管理的一个优秀特性,主要特点是,无论物理内存有多大,Linux 都将其充份利用,将 ...
- 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配
垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己 ...
- Windows内存管理和linux内存管理
windows内存管理 windows 内存管理方式主要分为:页式管理,段式管理,段页式管理. 页式管理的基本原理是将各进程的虚拟空间划分为若干个长度相等的页:页式管理把内存空间按照页的大小划分成片或 ...
- 内存管理概述、内存分配与释放、地址映射机制(mm_struct, vm_area_struct)、malloc/free 的实现
http://blog.csdn.net/pi9nc/article/details/23334659 注:本分类下文章大多整理自<深入分析linux内核源代码>一书,另有参考其他一些资料 ...
随机推荐
- 551. Student Attendance Record I
static int wing=[]() { std::ios::sync_with_stdio(false); cin.tie(NULL); ; }(); class Solution { publ ...
- 2018.08.17 洛谷P3135 [USACO16JAN]堡哞(前缀和处理)
传送门 有趣的前缀和. 数据范围中的n≤200" role="presentation" style="position: relative;"> ...
- UVa 12174 Shuffle (滑动窗口)
题意:你正在使用的音乐播放器有一个所谓的乱序播放功能,即随机打乱歌曲的播放顺序.假设一共有s首歌, 则一开始会给这s首歌随机排序,全部播放完毕后再重新随机排序.继续播放,依次类推.注意,当s首歌播放完 ...
- modelsim编译altera的库
http://www.cnblogs.com/LJWJL/p/3515586.html 在modelsim的安装目录下,把配置文件modelsim.ini的只读属性去掉,然后在modelsim中运行T ...
- struts2从浅至深(四)下载文件
1.创建下载文件动作类 2.配置struts 3.提供一个下载链接 4.下载页面 为什么文件名是链接名 只是以链接名显示,但文件的本身是个图片秩序改掉后缀名就可以了
- Delphi Dll 动态调用例子(3)-仔细看一下
http://blog.163.com/bxf_0011/blog/static/35420330200952075114318/ Delphi 动态链接库的动态和静态调用 为了让人能快速的理解 静态 ...
- jvm linux 时区设置
# 背景 在接入集团一个平台的时候,发现录制某个接口到测试环境回放,发现接口入参一致,一个start_day 一个end_day,但回放的时候会多调用一次数据库查询,很是奇怪: 查阅业务代码,发现确实 ...
- 设计模式之复合模式(Compound Pattern)
一.什么是复合模式? 在形式上,复合模式确实是多个模式的组合,但满足了这一条并不一定是复合模式,注意它的定义: 将多个模式结合起来形成一个“框架”,以解决一般性问题 一提到“框架”,可能最容易联想到的 ...
- asp.net 网站监控方案
前言:监控web网站方法有很多种,这篇文章说一下对windows服务器 asp.net网站的监控 采用的方案,Powershell + Influxdb + Grafana 1.PowerShell ...
- 用input标签 文件,多文件上传
单个文件,多个文件区别不大,只是需要把多个文件装在一个容器里面,循环遍历即可: 需要注意的 input 标签中name属性,一定要指定: 在这是 fileBase 需要确定method必须是pos ...