操作系统学习之内存管理

1.通过内存分段,内存分页来管理虚拟地址与物理地址之间的关系。
内存分段:
- 优点:产生连续的内存空间
- 缺点:内存碎片 内存交换的效率低
分段
- 段选择子
- 段内偏移量
- 段表来映射
分页
- 页号
- 页内偏移
- 把整个虚拟和物理内存空间切成一段段固定尺寸大小
- 页表来映射
页表存在MMU中,找不到–>缺页异常

2.分段为什么会产生内存碎片的问题
①外部内存碎片,多个不连续,新程序无法被装载(解决–>内存交换)
②内部内存碎片,所有都被装载,部分内存不常使用,导致内存浪费

3.分段为什么会产生内存交换效率低的问题?
对于多进程的系统,用分段的方式,容易产生内存碎片,不得不重新swap内存区域,会产生性能瓶颈,因为硬盘的访问速度比内存慢太多,每一次内存交换,都需要把一大段连续的内存数据写到硬盘。如果内存交换的师一个占内存空间很大的程序,整个机器会显得卡顿。

4.分页是怎么解决分段的内存碎片,内存交换效率低的问题?
采用分页,释放的内存以页为单位释放,不会产生无法给进程使用的小内存
通过动态换出换入,一次性写入磁盘的不多,效率就高了
只有在程序运行中,需要用到对应虚拟内存页里面的指令和数据,再加载到物理内存里

5.内存地址转换

  • 把虚拟地址分成页号和偏移量
  • 根据页号,从页表里查询对应的物理页号 xian
  • 直接拿物理页号,加上前面的偏移量,得到物理内存地址

6.简单分页有什么缺陷?
空间页表庞大(解决-->多级页表(存在时间开销))
例如:
32位,虚拟地址空间4GB 
假设一个页大小为4kb(2^12),那就要2^20个页,每个页表项要4个字节,整个4GB就要4MB的内存放页表

7.分了二级表,映射4GB要4kb(一级)+4Mb(二级),占用更多?
不对局部性原理
如果某个一级页表的页表项没用,那就不需要创建其二级页表
一级页表会覆盖到全部虚拟地址空间,二级页表在需要时创建

8.利用局部性,将最常访问的几个页表项存到访问最快的硬件。在CPU中加了一个专门存最常访问的页表项的cache,即TLB
内存管理单元芯片用来完成地址转换和TLB的访问与交互

9.段页式内存管理
实现方式:
①将程序划分为多个有逻辑意义的段—-》②页:段号 段内页号 页内位移 。
要得到物理地址要经过三次内存访问

  • 访问段表–》页表起始地址
  • 页表–》物理页号
  • 页号与页内位移组号–》物理地址

10.Inter x86
Intel X86 逻辑地址解析过程
Intel X86 逻辑地址解析过程

  • 逻辑地址
    程序使用,没被段式内存管理映射的地址
  • 线性地址,虚拟地址
    通过段式内存管理映射的地址

11.Linunx内存主要采用页式内存管理,不可避免涉及了段机制
Linux系统中每个段都是从0地址开始,所有的段起始地址一样,其中的代码面对的地址空间都是虚拟地址,因此屏蔽了处理器中的逻辑地址概念,段只被用于访问控制和内存保护

12.Linux虚拟地址空间分布
虚拟地址空间的内部又被分为内核空间和用户空间两部分
用户空间和内存空间
用户空间和内存空间
每个进程的内核空间都是一致的
虚拟内存空间分布
虚拟内存空间分布

总结

为了在多进程环境下,使得进程之间的内存地址不受影响,相互隔离,于是操作系统就为每个进程独立分配一套的虚拟地址空间,每个程序只关心自己的虚拟地址就可以,实际上大家的虚拟地址都是一样的,但分布到物理地址内存是不一样的。作为程序,也不用关心物理地址的事情。

每个进程都有自己的虚拟空间,而物理内存只有一个,所以当启用了大量的进程,物理内存必然会很紧张,于是操作系统会通过内存交换技术,把不常使用的内存暂时存放到硬盘(换出),在需要的时候再装载回物理内存(换入)。

那既然有了虚拟地址空间,那必然要把虚拟地址「映射」到物理地址,这个事情通常由操作系统来维护。

那么对于虚拟地址与物理地址的映射关系,可以有分段和分页的方式,同时两者结合都是可以的。

内存分段是根据程序的逻辑角度,分成了栈段、堆段、数据段、代码段等,这样可以分离出不同属性的段,同时是一块连续的空间。但是每个段的大小都不是统一的,这就会导致内存碎片和内存交换效率低的问题。

于是,就出现了内存分页,把虚拟空间和物理空间分成大小固定的页,如在 Linux 系统中,每一页的大小为 4KB。由于分了页后,就不会产生细小的内存碎片。同时在内存交换的时候,写入硬盘也就一个页或几个页,这就大大提高了内存交换的效率。

再来,为了解决简单分页产生的页表过大的问题,就有了多级页表,它解决了空间上的问题,但这就会导致 CPU 在寻址的过程中,需要有很多层表参与,加大了时间上的开销。于是根据程序的局部性原理,在 CPU 芯片中加入了 TLB,负责缓存最近常被访问的页表项,大大提高了地址的转换速度。

Linux 系统主要采用了分页管理,但是由于 Intel 处理器的发展史,Linux 系统无法避免分段管理。于是 Linux 就把所有段的基地址设为 0,也就意味着所有程序的地址空间都是线性地址空间(虚拟地址),相当于屏蔽了 CPU 逻辑地址的概念,所以段只被用于访问控制和内存保护。

另外,Linxu 系统中虚拟空间分布可分为用户态和内核态两部分,其中用户态的分布:代码段、全局变量、BSS、函数栈、堆内存、映射区。

学习链接