目录:
地址的动静态重定位
内存分配算法
程序的链接和装入(静态和动态)
逻辑地址和物理地址
虚拟内存,实际内存,内部外部碎片
地址的重定位:
程序执行时,必须将地址空间变为绝对地址才能访问系统分配的内存
地址重定位:操作系统把用户程序指令中的相对地址变换成为所在存储中的绝对地址的过程
地址重定位实现了:从逻辑地址到物理地址的转换
按照重定位时机分类:静态重定位、动态重定位
- 地址的静态重定位
定义:在程序运行之前,为用户程序实行了地址重定位工作
一般由操作系统中的重定位装入程序完成
重定位装入程序的输入:用户把自己的作业链接装配成一个相对于 0 编址的目标程序
过程:
重定位装入程序根据当前内存的分配情况,按照分配区域的起始地址逐一调整目标程序指令中的地址部分。目标程序在经过重定位装入程序加工之后,不仅进入到分配给自己的绝对地址空间中,而且程序指令中的地址部分全部进行了修正,反映出了自己正确的存储位置,保证了程序的正确运行
特点:
在装入前实现调整
地址要有标识
每次装入都要进行定位
装入后地址不再改变(静态)
- 地址的动态重定位
定义:在程序执行寻址时进行重定位,访问地址时,通过地址变换机构改变为内存地址
用户程序原封不动的装入内存,运行时再完成地址的定位工作
动态重定位需要硬件的支持,要求系统中配备定位寄存器和加法器
特点:
程序可装入任意内存区域(不要求占用连续的内存区)
只装入部分程序代码即可运行
改变系统时不需要改变程序(程序占用的内存空间动态可变,只需要改变定位寄存器中的值即可)
程序可方便共享
最优适应算法:通常将空闲区按长度递增顺序排列。查找时总是从最小一个空闲区开始,直到找到满足要求的分区为止。此算法保证不会分割一个更大的区域,使得装入大作业的要求容易得到满足。补充:最先适应算法:通常将空闲区按地址从小到大排列。查找时总是从低地址开始,可使高地址尽量少用,以保持一个大空闲区,有利于大作业的装入;缺点是内存低地址和高地址两端的分区利用不平衡,回收分区较麻烦。空闲区分割给作业使用,其优点是使剩下的空闲区不致于太小,这样有利于中小型作业,但不利于大作业。这些都属于可变分区分配算法,当然还有下次适应分配算法和快速适应分配算法。注:这些算法理解即可。最坏适应算法:通常将空闲区按长度递减顺序排列 。查找时从最大的一个空闲区开始,总是挑选一个最大的
- 一般情况下虚拟内存的大小大于物理内存与外部存储的大小总和。
比如对于一台80x86上运行的32位Linux,其可寻址的物理地址空间为4GB,虚存大小上限为 4GB * 进程数上限。
- 内存管理
内存管理的功能有:
- 内存空间的分配与回收:由操作系统完成主存储器空间的分配和管理,使程序员摆脱存储分配的麻烦,提高编程效率。
- 地址转换:在多道程序环境下,程序中的逻辑地址与内存中的物理地址不可能一致,因此存储管理必须提供地址变换功能,把逻辑地址转换成相应的物理地址。
- 内存空间的扩充:利用虚拟存储技术或自动覆盖技术,从逻辑上扩充内存。
- 存储保护:保证各道作业在各自的存储空间内运行,.互不干扰。
在进行具体的内存管理之前,需要了解进程运行的基本原理和要求。
程序装入和链接
创建进程首先要将程序和数据装入内存。将用户源程序变为可在内存中执行的程序,通常需要以下几个步骤:
- 编译:由编译程序将用户源代码编译成若干个目标模块。
- 链接:由链接程序将编译后形成的一组目标模块,以及所需库函数链接在一起,形成一个完整的装入模块。
- 装入:由装入程序将装入模块装入内存运行。
这三步过程如图3-1所示。
图3-1 对用户程序的处理步骤
程序的链接有以下三种方式:
- 静态链接:在程序运行之前,先将各目标模块及它们所需的库函数链接成一个完整的可执行程序,以后不再拆开。
- 装入时动态链接:将用户源程序编译后所得到的一组目标模块,在装入内存时,釆用边装入边链接的链接方式。
- 运行时动态链接:对某些目标模块的链接,是在程序执行中需要该目标模块时,才对它进行的链接。其优点是便于修改和更新,便于实现对目标模块的共享。
内存的装入模块在装入内存时,同样有以下三种方式:
1) 绝对装入。在编译时,如果知道程序将驻留在内存的某个位置,编译程序将产生绝对地址的目标代码。绝对装入程序按照装入模块中的地址,将程序和数据装入内存。由于程序中的逻辑地址与实际内存地址完全相同,故不需对程序和数据的地址进行修改。
绝对装入方式只适用于单道程序环境。另外,程序中所使用的绝对地址,可在编译或汇编时给出,也可由程序员直接赋予。而通常情况下在程序中釆用的是符号地址,编译或汇编时再转换为绝对地址。
2) 可重定位装入。在多道程序环境下,多个目标模块的起始地址通常都是从0开始,程序中的其他地址都是相对于起始地址的,此时应釆用可重定位装入方式。根据内存的当前情况,将装入模块装入到内存的适当位置。装入时对目标程序中指令和数据的修改过程称为重定位,地址变换通常是在装入时一次完成的,所以又称为静态重定位,如图3-2(a) 所示。
图3-2 重定向类型
静态重定位的特点是在一个作业装入内存时,必须分配其要求的全部内存空间,如果没有足够的内存,就不能装入该作业。此外,作业一旦进入内存后,在整个运行期间不能在内存中移动,也不能再申请内存空间。
3) 动态运行时装入,也称为动态重定位,程序在内存中如果发生移动,就需要釆用动态的装入方式。装入程序在把装入模块装入内存后,并不立即把装入模块中的相对地址转换为绝对地址,而是把这种地址转换推迟到程序真正要执行时才进行。因此,装入内存后的所有地址均为相对地址。这种方式需要一个重定位寄存器的支持,如图3-2(b)所示。
动态重定位的特点是可以将程序分配到不连续的存储区中;在程序运行之前可以只装入它的部分代码即可投入运行,然后在程序运行期间,根据需要动态申请分配内存;便于程序段的共享,可以向用户提供一个比存储空间大得多的地址空间。
逻辑地址空间与物理地址空间
编译后,每个目标模块都是从0号单元开始编址,称为该目标模块的相对地址(或逻辑地址)。当链接程序将各个模块链接成一个完整的可执行目标程序时,链接程序顺序依次按各个模块的相对地址构成统一的从0号单元开始编址的逻辑地址空间。用户程序和程序员只需知道逻辑地址,而内存管理的具体机制则是完全透明的,它们只有系统编程人员才会涉及。不同进程可以有相同的逻辑地址,因为这些相同的逻辑地址可以映射到主存的不同位置。
物理地址空间是指内存中物理单元的集合,它是地址转换的最终地址,进程在运行时执行指令和访问数据最后都要通过物理地址从主存中存取。当装入程序将可执行代码装入内存时,必须通过地址转换将逻辑地址转换成物理地址,这个过程称为地址重定位。
内存保护
内存分配前,需要保护操作系统不受用户进程的影响,同时保护用户进程不受其他用户进程的影响。通过釆用重定位寄存器和界地址寄存器来实现这种保护。重定位寄存器含最小的物理地址值,界地址寄存器含逻辑地址值。每个逻辑地址值必须小于界地址寄存器;内存管理机构动态地将逻辑地址与界地址寄存器进行比较,如果未发生地址越界,则加上重定位寄存器的值后映射成物理地址,再送交内存单元,如图3-3所示。
当CPU调度程序选择进程执行时,派遣程序会初始化重定位寄存器和界地址寄存器。每一个逻辑地址都需要与这两个寄存器进行核对,以保证操作系统和其他用户程序及数据不被该进程的运行所影响。
- 虚拟储存器
虚拟存储器基于局部性原理,在程序运行时,可以将程序的一部分装入内存,而将其余部分留在外存,就可以启动程序执行。在程序执行过程中,当访问的信息不在内存时,由操作系统将所需的部分调入内存,然后继续执行。另一方面,操作系统将内存中暂时不使用的内容换出到外存上,从而腾出空间存放将要调入的信息。
可行性基础:虚存的可行性基础是计算机中著名的局部性原理。 局部性原理表现在以下两个方面: ☞ 时间局部性:如果程序中的某条指令一旦执行,不久之后该指令可能再次执行;如果某数据被访问过,不久之后该数据可能再次被访问。产生时间局部性的典型原因是程序中存在着大量的循环操作。 ☞ 空间局部性:一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也将被访问,即程序在一段时间内所访问的地址,可能集中在一定的范围内,这是因为指令通常是顺序存放、顺序执行的,数据也一般是以向量、数组、表等形式聚簇存储的。
实现虚存最主要的技术是(部分对换)。
虚拟内存的特征是:
1.虚拟扩充 即不是物理上而是逻辑上扩充了内存容量
2.部分装入 即每个作业不是全部一次性地装入内存,而是只装入一部分
3.离散分配 即不必占用连续的内存空间,而是“见缝插针”
4.多次对换 即所需的全部程序和数据要分成多次调入内存
计算机系统的虚拟存储器,其最大容量取决于机器的地址结构(即页面大小)及系统的逻辑地址结构,而实际容量则取决于系统中内、外存容量总和。
- 内部碎片和外部碎片
在内存管理中,
内部碎片是已经被分配出去的的内存空间大于请求所需的内存空间。
外部碎片是指还没有分配出去,但是由于大小太小而无法分配给申请空间的新进程的内存空间空闲块。
固定分区存在内部碎片,
可变式分区分配会存在外部碎片;
页式虚拟存储系统存在内部碎片;
段式虚拟存储系统,存在外部碎片
为了有效的利用内存,使内存产生更少的碎片,要对内存分页,内存以页为单位来使用,最后一页往往装不满,于是形成了内部碎片。 为了共享要分段,在段的换入换出时形成外部碎片,比如5K的段换出后,有一个4k的段进来放到原来5k的地方,于是形成1k的外部碎片。
- 内存(主存)直接给CPU提供存储,高速,低容量,价格贵,不能永久保存数据,断电消失,需要从辅存中重新调入数据。
外存(辅存)给主存提供数据,低速,大容量,价格低,能永久保存数据。
- 可重入码:当被多个线程调用的时候,不会引用任何共享数据,他们是线程安全的。(注意与线程安全做区别 可重入是线程安全的真子集)
页式管理有:
静态页式管理;
动态页式管理;
其中,静态页式管理是在作业或进程执行前,把作业或进程全部装进内存中,如果内存中可用页面数小于请求页面数,该作业或进程等待。
动态页式管理不会把作业或进程一次性全部装进内存,只装入被反复调用或执行的部分,其他部分在执行过程中动态装入。
- 虚拟存储器的最大容量 = min(内存+外存,2^n)。n为计算机的地址总线位数。
虚拟地址对应于物理存储空间的大小,因而可以虚拟出看起来很大的内存空间,这里虚拟地址的地址结构是:
31---页号---12---位移量w---0,这里的地址长度正好是操作系统的内存位数,所以可以知道最大寻址为2的32次方b,对应于kb,mb,gb的换算式如下:
2^10b = 1kb
2^20b = 1mb = 1kb*2^10
2^30b = 1gb = 1mb*2^10
这里2^32 = 2^2*1gb = 4gb
为什么静态重定位后的程序在内存中不能移动?为什么动态重定位的程序在内存中可以移动?
参考答案
静态重定位后的程序在内存中不能移动的原因如下:静态重定位后的程序的代码发生了变化,由原来逻辑地址的程序已经变为物理地址的程序,按物理地址的方式运行,因此不能再进行移动。动态重定位的程序在内存中可以移动的原因如下:动态重定位是在程序运行过程中由硬件进行地址变换,变换的结果存放在内存地址寄存器中。程序代码并没有发生变化,仍然是逻辑地址的代码,按逻辑地址的方式运行。因此,在内存中移动程序代码之后,仅需要根据代码新的起始位置,重新设定基地址寄存器的值。
虚存管理与实存管理的根本区别是什么?
参考答案
根本区别就在于,虚拟管理允许部分装入和部分对换,而实存管理不允许这样做。所谓"部分装入",指的是一道应用程序不是全部装入内存以后才开始执行而是只装入其中一部分,甚至一点都不装入就开始运行,然后在运行的构成中根据需要逐步的装入其余部分;"部分对换",指的是当内存已满而又有新的将"部分"需要装入时,要把已在内存的某一"部分"换出去,以腾出空间存放新来者。部分装入和部分对换的结果是可以用较小的内存运行较大的程序。实存管理则不同,它所要求的是整体装入。
就虚存回答以下问题: (1)虚存的应用背景是什么? (2)虚存的可行性是什么? (3)实现虚存的主要技术是什么? (4)虚存可以有多大?
参考答案
(1)虚存的应用背景是用小内存运行大程序。这里的"大程序"是指比整个内存用户空间还要大的程序,它可以是一道程序,也可以是多道程序之和。(2)虚存的可行基础是程序运行的局部性原理。(3)实现虚存的主要技术是部分装入、部分对换、局部覆盖、动态重定位。(4)从原理上讲,虚存空间就是CPU逻辑地址所给出的空间。例如,逻辑地址是25位,则虚存空间就是225=32MB;但实际的虚拟存储器的容量还要受辅存和内存空间之和的限制,实际的虚存容量不能超过这两个物理空间之和。
怎样对内存进行分区?
参考答案
对内存空间的划分是可以静态的,也可以动态的;可以是等长的,也可以不等长。静态划分是指系统运行之前就将内存空间划分成若干区域,通常,分配给进程的内存可能比进程实际所需的区域长。动态划分是在系统运行过程中才划分内存空间。这样,系统可按进程所需要的存储空间大小为其分配恰好满足要求的一个或多个区域。等长分区是将存储空间划分为若干个长度相同的区域。不等长分区则是将存储空间划分若干个长度不同的区域。
- 内存泄漏
A,内存泄露是程序设计的bug,不是操作系统的问题
B,内存泄露跟线程数无关
C,内存泄露是进程申请了内存却没有释放。导致占用内存无限上升
D,进程退出之前释放申请的内存,不代表进程运行过程中没有内存泄露
E,java是自动管理内存的,但是也会有内存泄露,比如加入HashMap的对象hash值改变了就无法从HashMap中remove,这就造成了内存泄露