《初学者对内存管理的常见疑惑》


20220710.No.5122


https://www.xuetangx.com/learn/XIYOU08091001441/XIYOU08091001441/10321548/video/17342639

大家好,我是奔跑吧Linux内核一书的作者,笨叔,很高兴能在陈莉君老师的《linux内核分析与应用》,这门慕课中和大家分享一点关于内存管理的理解。陈老师在这个课程里已经对linux内核的内存管理做了很全面和系统的介绍,那,我在这期节目想和大家聊聊,初学者对内存管理的常见8大疑惑,这些疑惑是我多年工作经验的总结,它们可能是这门课 期末考试的必考内容,也有可能是以后你们职场技术面试的必考题哟,我们一起来看看都有哪些疑惑吧。


P1:疑惑一:关于虚拟地址

我觉得初学者对内存管理最常见的第一个疑惑是关于虚拟地址?比如说,为什么现代处理器访问的地址是虚拟地址而不直接采用物理地址?第二问题,为什么处理器内部需要标配一个MMU的硬件单元?

这两个问题需要同学们对计算机体系结构的发展历史需要有一点的了解,那么会对这个问题容易理解一些。在上个世纪50年代,那时候系统软件还没有操作系统的概念,系统只有一个进程,我们把它称为单道处理系统,用户程序总是加载到同一个内存地址上运行,所以内存管理很简单。实际上不需要任何的内存管理单元,程序使用的地址就是物理地址,而且也不需要地址保护。但是缺点也很明显:第一点,无法运行比实际物理内存大的程序;其二,系统只运行一个程序,造成资源浪费;其三,无法迁移到其他的计算机中运行。

那么,后来出现多道处理系统,系统可以同时运行多个进程。在内存管理方面,因为要处理多个进程的问题,所以历史上出现了固定分区和动态分区两种技术。

所谓固定分区,就是在系统编译阶段,把内存被划分成许多静态分区,进程可以装入大于或者等于自身大小的分区。这个实现简单,操作系统管理开销也比较小。


P2:动态分区法

固定分区方法有缺点,人们自然就想到了动态分区的方法。动态分区的思想也比较简单,就是在一整块内存中首先划出一块内存是给操作系统本身使用,那么剩下的内存空间给用户进程使用。当第一个进程A运行时,先从这一大片内存中切割一块进程A需要的内存大小,给进程A使用。当第二个进程B准备运行时,我们可以从剩下的空闲内存中继续切割一块进程B所需要的内存,给进程B使用,依次类推。这样进程A和进程B以及后面进来的进程就可以实现动态分区了。

我们来看这个图,假设现在有一块32MB大小的内存,一开始操作系统使用了最低的4MB大小,剩余的内存要留给4个用户进程使用(如图(a)所示)。进程A使用了操作系统往上的10MB内存,进程B使用了进程A往上的6MB内存,进程C使用了进程B往上的8MB内存。剩余的4MB内存不足以装载进程D,因为进程D需要5MB内存((b)所示),那么这样,这个内存末尾就形成了第一个空洞。假设某个时刻,操作系统需要运行进程D,这时系统中没有足够的内存,就需要选择一个进程来换出,以便为进程D腾出足够的内存空间。假设操作系统选择进程B来换出,这样进程D就装载到了原来进程B的地址空间里,但是呢,产生了第二个空洞(如图(c)所示)。假设操作系统某个时刻需要进程B运行,也需要选择一个进程来换出,假设进程A被换出,那么系统中又产生了第三个空洞(如图(d)所示)。这个就是动态分区法的工作原理。


P3:直接使用物理地址的缺点

刚才提到了固定分区法和动态分区法都是处理器直接访问的物理地址的,但是呢,这种内存管理的方式对于现代操作系统来说,充满了挑战,这些挑战,我大概列举3个方面挑战:

1. 进程地址空间保护(isolation)和安全问题(security)。

所有的用户进程都可以访问全部的物理内存,如果有恶意的程序,那么它可以修改其他程序的内存数据,这样破坏了系统管理软件和其他进程的内部数据。即使系统里所有的进程都不是恶意进程,但是进程A依然可能不小心修改了进程B的数据,从而导致进程B运行崩溃。这明显违背了“进程地址空间需要保护”的原则,也就是地址空间要相对独立。所以,操作系统需要保证,每个进程的地址空间都应该受到保护,不应该被其他进程有意或者无意地伤害。

2. 内存使用效率低。

如果即将要运行的进程所需要的内存空间不足,就需要选择一个进程进行整体换出,这种机制导致有大量的数据需要换出和换入,效率非常低下,通常换出是把数据写入到交换分区,导致大量的磁盘IO。

3. 程序运行地址重定位问题。

从前一页的ppt里看到,进程在每次换出换入时运行的地址都是不固定的,这给程序的编写带来一定的麻烦,因为访问数据和指令跳转时的目标地址通常是固定的,这就需要重定位技术了。

上面三个问题,如果纯粹从软件来解决,貌似很难,所以人们开始思考是否可以从处理器体系结构,这个的角度来思考,如何解决问题。


Pn:地址空间的抽象

对于一个进程,站在内存使用的角度来看,大概有三个地方需要用到内存:

  1. 代码段,数据段用来存储程序本身需要的数据。

  2. 栈。程序运行时候,需要分配一个内存空间来保存 函数调用关系,保存局部变量、函数参数以及函数返回值等内容,这些也是需要消耗内存的。

  3. 堆空间。程序运行时候,需要动态分配程序需要使用的内存,比如存储 程序需要用的数据等等。

不管是刚才提到的静态分区法,还是动态分区法,对于一个进程来说,都需要包含上述三种内存。但是,如果我们直接使用物理内存的话,我们在编写这样一个程序时候,就需要每时每刻去关心: 分配的物理内存地址是多少,内存空间够不够?等等这些问题。

后来,人们对内存也有一个伟大的抽象,就是把上述三个用到的内存,抽象成地址空间或者虚拟内存,也就是说&

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值