内存管理 连续分配--固态、动态分配 离散分配--基本分页存储、基本分段存储、段页式存储

参照:https:// ** .bilibili.com/video/av31584226/?p=13

什么叫内存?有什么功效?

内存是用以存取数据的硬件配置,程序运行前必须先放进内存中才可以被cpu解决。因为外存的获取速率迟缓,与快速的cpu不配对,因此发生内存这类正中间缓存部件,那样就可以缓解cpu和外存中间的分歧。

当好几个程序流程高并发实行时,每个程序流程的信息都是会储放到内存中。那麼,如何区分每个程序流程的数据资料是储放在哪儿呢?

解决方法:给内存的数据存储器编详细地址。因此就拥有内存详细地址的定义。

内存详细地址从0逐渐,每一个详细地址相匹配一个数据存储器。内存中也有一个一个的小屋子,每一个小屋子便是一个“数据存储器”。那麼数据存储器有多大呢?

这一需看这一电子计算机是“按字节数编址”或是“按字编址”。假如电子计算机“按字节数编址”,则每一个数据存储器尺寸为1字节数,即1B,即8个二进制位,8bit.如果是按字编址,那麼就得看这一电子计算机的字节为多久了,字节很有可能为16位,32位, ** 位。假如字节为16位,那麼一个数据存储器的尺寸为1个字,则每一个字的尺寸为16个二进制位。

下边另附视频里的照片加重了解。

随后来普及一下基本知识:

在电脑操作系统之中,1k=2的10次方 1M=2的20次方 1G=2的30次方

一台计算机有4GB内存,表明内存中可以储放4 2的30次方个字节数。如果是按字节编址得话,也就是有4 * 2的30次方=2的32次方个小屋子。因此这一详细地址得用32个二进制位来表明。

拥有上边的概念以后,大家一起来看看内存在进程的运作流程之中具有了什么作用?

大家应用程序设计语言撰写的编码通过编译器以后会产生和这种编码对等的计算机指令。例如常用的X=X 1;

假如对汇编程序略微有一些认识的人应当都能不错的了解这种。这些计算机指令是由机器语言--二进制撰写的,能立即被cpu鉴别,cpu依据这种命令来进行一定的实际操作。

如下图:

追忆一下前边的基本知识,进程是由代码段,数据信息段,进程操纵块构成的,随后进程里的这些命令都放到代码段中,数据信息段则用于储放自变量之类的。这一X=X 1,便是先把自变量X从内存详细地址中拿出来,随后传输到存储器之中,随后在存储器之中开展加减法命令,随后再把解决好的X从存储器传输到原先内存中的部位,也就是遮盖。这就是cpu按序程序执行段中的命令的結果。一般命令的第一个字节数表明这个是什么实际操作,例如数据信息传输或加减法,第二位和第三位都表明详细地址。

在上面的案例中,命令中立即提供了X的具体储放详细地址(也就是MAC地址),但实际上在转化成计算机指令的情况下并不了解该进程的信息会被放进什么位置。因此编译程序产生的命令中一般是应用逻辑地址(即相对性详细地址)。

随后充分考虑大伙儿也许对MAC地址和相对性详细地址沒有了解,这儿我以前学选编都读过了,就不会再详说了,给大伙儿视频里的demo了解一下:

换句话说一个进程有自身的开始详细地址,随后进程里边的计算机指令中的详细地址全是相比于这一开始详细地址来讲的。那样内存和进程的监管就非常简单,进程只需解决自身所具有的内存就可以。

随后让我们一起来看看从写程序到程序执行究竟发生什么事: 下边是平面图,觉得有利于了解。

一个工程项目里有好几个控制模块,每个源码文档通过编译程序后转化成分别相匹配的序列号,通过连接后把每个控制模块组成到一起(包括了需要的函数库),产生完善的装入控制模块。随后由装入程序流程把装入控制模块装入内存中运作。装入控制模块便是大家常用的.exe文件。大伙儿留意这儿的详细地址:装入后进入了一望无际的内存之中,变成这其中的一份子。

完成上边的最终面的装入:即详细的逻辑地址到MAC地址的全过程由三种方法:(不做关键了解,没意识到实际意义)

1.肯定装入:编译程序时造成绝对地址(此技术性或是单道程序流程时采用的,那时候还没电脑操作系统)

2.可多次精准定位装入:装入时将逻辑性网络地址转换为MAC地址(应用于前期的多道批处理命令电脑操作系统)

3.动态性运作时装入:运行时将逻辑性网络地址转换为MAC地址,需设定重精准定位存储器(现代操作系统)

随后大家来宣布看一下内存管理方法。分四个方面:

1.电脑操作系统承担内存室内空间的分配和回收利用。即新造成的进程该给它分配哪块内存,进程完毕后如何回收利用,如何纪录哪儿的内存是空闲,哪里的内存在被占有。

2.例如全部的进程运作起來必须60G的内存,可是计算机的具体内存仅有8GB,照理说应当要把60G的内存都载入进内存之中,但是本来不足,那为什么这种进程可以所有运作起來呢?这也是电脑操作系统的虚构性,即虚拟现实。因此电脑操作系统必须给予某类技术性从逻辑关系上对内存开展扩大。

3.为了更好地写程序的便捷,程序猿只要实际操作逻辑地址,而电脑操作系统要承担逻辑地址到MAC地址的变换。那样程序猿就不用关注具体物理学内存的运用状况。

4.电脑操作系统必须给予内存维护作用,确保各进程在分别的内存空间内运作,互相不影响。

下边是一个专业知识一览:

前边早已对第三层面的网络地址转换干了基本上简述,如今看来第四层面的内存维护。

如下图:内存一般分电脑操作系统自身应用的内存,也有每个进程应用的内存。为了更好地内存维护,因此进程1不可以浏览电脑操作系统和其他进程的内存室内空间。

内存维护有2种完成方法:

方式1:cpu中设定一对左右县存储器,储放进程的上最低值详细地址。进程的命令要浏览某一详细地址时,cpu查验是不是越境。

方法2:应用重精准定位存储器和界地址寄存器开展越境查验,实际上就相近逻辑地址和MAC地址的定义。类似吧。看下面的图了解一下就行。

随后大家看来内存管理方法第二层面的内存扩大技术性:

有三种技术:1.遮盖 2.互换 3.虚似内存 (这一留到后边讲)

1.遮盖:

观念:将程序流程分成好几个段(多个控制模块),常见的段长驻内存,不常见的段在必须时再加入内存。

内存中分成一个“固定不动区”和多个“遮盖区”。

必须长驻内存的段放到固定不动区中,加入后不会再调成(除非是运作完毕)

不经常出现的段放到遮盖区,必须时加入内存,用不上是调成内存。

(实际上便是怎样在比较有限的区域内做更多的事儿的问题,非常好了解)

下边是实际操作的平面图:

核心内容便是不太可能被与此同时浏览呢的代码段共享资源同一个遮盖区。

但因为这务必由程序猿申明遮盖构造,电脑操作系统进行全自动遮盖。缺陷:对消费者不全透明,提升了客户程序编写压力,遮盖技术性只用以初期的电脑操作系统,如今现已撤出演出舞台。

2.互换

当内存室内空间焦虑不安时,系统软件将内存中挂起来的进程(也就是储放在电脑操作系统阻塞队列里的进程)临时掉换外存,把外存中已具有运作情况的进程换入内存。实际上便是进程在内存与硬盘间的信息生产调度。 可是进程的PCB信息内容还会继续储存在阻塞队列之中,这时PCB还会继续加上进进程在外存中存放的部位。

回收器的初级生产调度便是:感觉要将哪个处在挂起状态的进程再次加入内存。

那麼进程会被放进外存的哪儿呢?

一般硬盘系统软件都被分成调换区和文档区,文件区专业用以放置文档,调换区用以储存这种进程。文档区追求完美储存空间的使用率,因此选用室内空间选用离散变量分配方法。而调换区追求完美进程间的互换速率,因此才有持续分配方法。总而言之,调换区的io速率比文档区迅速。

一般掉换的进程全是堵塞态的进程或是优先较为低的进程。

3.虚似内存技术性因为比较多,就没有这儿开展解读了,后边专业拿一篇文章开展解读。

随后大家看来内存管理方法的第一层面:内存的分配和回收利用。

内存的分配和回收分成2种方法:

1.持续分配管理方式 2.非连续分配管理方式

持续分配:指为客户进程分配的务必是一个持续的内存室内空间。

持续分配管理方式又分成

1.单一持续分配

2.固定不动分区分配

3.动态性分区分配

单一持续分配:在单一连续分配方法中,内存被分成系统软件区和用户区。系统区通常坐落于内存的低详细地址一部分,用以储放电脑操作系统有关数据信息;用户区用以储放进程有关数据信息。内存中只有有一道可执行程序,用户程序独享全部用户区室内空间(即不兼容高并发)

优势:完成简易;无外界残片;可以选用遮盖技术性扩大内存;不一定必须内存维护。

缺陷:只有用以多用户单任务的电脑操作系统之中,有内部结构残片(例如分配给某一进程一片内存,可是却有一部分没有用上,这一部分就称为内存残片),储存器使用率极低。由于例如全部内存区全是分配给这一个客户进程,但是它却只运用了一小部分,因此储存器使用率极低。

下边是平面图:

固定不动分区分配:

20世际60时代发生了适用多道程序的系统软件,为了更好地能在内存中装入多道程序,且这种程序流程中间不容易互相影响,因此将全部客户室内空间划定为多个固定不动尺寸的分区,在每一个分区中只装入一道工作,那样就建立了最初的、非常简单的一种可运作多道程序的内存管理方式。

固定不动分区分配又分配分区尺寸相同和分区大小不一二种方法。

分区尺寸相同:欠缺操作灵活性,可是很合适用以一台计算机系统控制好几个同样目标的场所(例如冶炼厂有n个同样的炼铁高炉,就可把内存分成n个尺寸相同的地区储放n个炼铁高炉管理程序)。假如存进比较大的进程,只有回绝或是应用遮盖技术性拓展内存尺寸。

分区大小不一:提升了操作灵活性,可以达到不一样尺寸的进程要求。依据经常在系统软件中运作的工作尺寸状况做好区划(例如好几个小分区、适当中等水平分区、很多大分区)

应用固定不动分区分配,就必须电脑操作系统创建一个算法设计--分区表明表,来完成每个分区的分配与回收利用。每一个表项相匹配一个分区,通常按分区尺寸来拍排序。每一个表包含相匹配分区的尺寸、开始详细地址、情况(是不是早已分配)。如下图:

当某可执行程序要装入内存时,由电脑操作系统核心程序流程依据可执行程序尺寸查找该表,从这当中找出一个能达到尺寸的,未分配的分区,将之分配给改程序流程,随后改动情况为“已分配”

优势:完成简易,无外界残片。

缺陷:1.当可执行程序很大时,很有可能全部分区都不可以满足需求,这时迫不得已选用遮盖技术性来处理,但这又会减少特性 2.会造成内部结构残片,内存使用率低。(例如进程必须10M内存,这儿适合的仅有12M内存,那麼那2M内存只有消耗了)

下边是这两种方法的平面图:

动态性分区分配:

动态分区分配又称之为可变分区分配。这类分配方法不容易事先区划内存分区,反而是在进程装入内存时,依据进程尺寸动态性地创建分区,并使分区的尺寸恰好适合进程的必须。因而系统软件分区的尺寸和数量是可变的。

随后由动态性分区分配大家明确提出下边的问题并处理:

1.系统软件要应用怎样的算法设计来纪录内存的运用状况?

二种较常用的算法设计:1.空闲分区表 2.空闲分区链

空闲分区表:每一个空闲分区相匹配一个表项。表项中包括分区号,分区尺寸,分区开始详细地址等信息内容。

空闲分区链:每一个分区的初始一部分和结尾一部分各自设定前向表针和后向指针,开始一部分还可纪录分区尺寸等信息内容。

下列图为案例:

空闲分区表:

空闲分区链:

比较好了解,这儿也不细讲了。

问题2:当有很多个空闲分区都能符合要求时,应当选取哪个分区开展分配?例如:

随后有一个只要4M内存尺寸的进程来啦,那麼该给在哪个空闲分区分配这4M内存?

这儿是要根据一定的动态性分区分配优化算法,从空闲分区表(或空闲分区链)中挑选出一个分区分配给改作业。有因为分配优化算法系统对特性有较大的危害,因而我们对它完成了普遍的科学研究。这里有四种动态性分区分配优化算法。因为內容比较多,因此后边再开展叙述。

问题3:怎样开展分区的分配与回收利用?

假定系统软件使用的是空闲分区表:

先详细介绍分区的分配时表的更改状况:

下边这幅图表明了一种状况:

即当把5M插进到第一空闲分区20M里边,立即改动第一分区的分区尺寸和开始详细地址就可以。

另一种状况如下图:

即恰好把最后一个空闲分区铺满,那麼立即删掉最后一个空闲分区就可以。

随后看来表的回收利用状况:即一个进程完毕后,撤除这一进程的内存后,分区空闲表该咋变。这儿考虑到了四种状况:回收利用地区前边便是空闲地区(合拼到前边分区中),回收利用地区后边是空闲地区(合拼到后边分区中),回收利用地区前后左右全是空闲地区(2个分区合拼正中间变为更高的分区),回收利用地区前后左右也没有空闲地区(建立新的列)

我认为这一理所应当地应该是那样变。。因此也不拿图出去演试了终究非常简单。

好啦,问题到这就所有结束。随后让我们一起来看看动态性分区的内存残片的问题。

动态性分区分配沒有内部结构残片,可是有外界残片。

内部结构残片:分配给某进程的内存地区中,假如很多一部分没有用上。

外界残片:就是指内存中的一些空闲分区因为过小而无法运用。

换句话说,例如因为进程的添加和完毕,内存中流下来了分散化的内存地区,这种分离的内存地区加起來可以达到一个大进程的插进,可是因为进程必须的是一整块持续的内存室内空间,因而这种残片不可以达到进程的要求。

可以根据紧密技术性来处理外界残片。即把进程挪动,使内存残片聚集到一起,随后新的大进程就能插入了。这时应用的是动态性运作时装入的装入方法,进程的MAC地址,开始详细地址这种数据都需要更改。可是“紧密”的時间成本很高。

嗯,持续分区分配就讲到这儿了。

随后大家而言前边说的內容比较多的四种动态分区分配算法:

1.首次适应算法

2.最佳适应算法

3.最坏适应算法

4.临近适应算法

.......后面补充

看完前面那么多的连续分配管理方式,现在来看非连续的分配管理方式:

考虑支持多道程序多道的两种连续分配方式:

1.固定分区分配:缺乏灵活性,会产生大量的内部碎片,内存的利用率很低。

2.动态分区分配:会产生很多外部碎片,虽然可以用“紧凑”技术来处理,但是“紧凑”的时间代价很高。

所以,如果允许将一个进程分散地装入到许多不相邻的分区中,便可充分的利用内存,而无需再进行紧凑。基于这一思想,产生了非连续的分配方式。或者称为“离散分配方式”。

非连续分配方式:为用户进程分配的可以是一些分散的内存空间。

非连续分配方式又分为三种:

1.基本分页存储管理

2.基本分段存储管理

3.段页式存储管理

首先我们来看基本分页存储管理:

下面是一张过渡的理解图片,就不细说了。

然后我们来看基本分页存储的基本概念:

它将内存空间分为一个个大小相等的分区(比如:每个分区4KB),每个分区就是一个“页框”,或称“页帧”、“内存块”、“物理块”。每个页框有一个编号,即"页框号"(或者“内存块号”、页帧号、“物理块号”)。页框号从0开始。

将用户进程的地址空间也分为与页框大小相等的一个个区域,称为“页”或“页面”。每个页面也有一个编号,即“页号”,页号也是从0开始。

(注:进程的最后一个页面可能没有一个页框那么大。因此页框不能太大,否则可能产生过大的内部碎片)

操作系统以页框为单位为各个进程分配存储空间。进程的每个页面分别放入一个页框中,也就是说,进程的页面与内存的页框有一一对应的关系。

以下为示意图:先是进程的页面

然后是内存的页框:

进程的以页面为最小单位放入内存的页框后如下所示:

各个页面不必连续存放,也不必按先后顺序来,可以放到不相邻的页框中。

我想,大家和我看完这种方式后第一想法应该都是:

哇,这样的话逻辑地址怎么转化为物理地址?比起之前来应该要麻烦很多吧?

然后我们来解决这个问题:

前面的连续分配方式我们是使用动态重定位的方式进行装入,即装入时指令依然是逻辑地址,等到执行的时候再再进行地址转换。系统有一个重定位寄存器,存放装入模块存放的起始位置。即等到执行的时候,由于进程采取的是连续内存分配方式,所以cpu会自己把从指令中取出的地址加上重定位寄存器中的地址,然后去操作结果的那个地址。前面的cpu就是这样实现逻辑地址到物理地址的转换的。

然后,到非连续分配方式我们就是这样计算的了,其实大家仔细想想也能想到:

举个具体的例子:

比如进程的页面大小为50B,然后要定位这个进程逻辑地址为80B对应的物理地址在哪里?

直接这样看,我们肯定就知道,很明显80B在第1个页面内(从0开始),找到第一个页面的起始地址(肯定在操作系统中有数据结构存储好了),然后加上30B就找到了。

整理的思路如下:

1.先找到在逻辑地址在进程的哪个页面,计算方式就是:逻辑地址/页面大小

2.然后找到逻辑地址在该页面内的偏移地址: 逻辑地址%页面大小

3.然后从操作系统中找到进程对应页面的起始地址加上去即可。

然后补充:为了方便计算上面的这些数值,一般取页面大小为2的n次方。比如4KB=2的12次幂。

在操作系统中存储页面信息的数据结构叫页表:

如下图可方便理解:

1.一个进程对应一张页表。

2.进程的每一页对应一个页表项。

3.每一个页表项由“页号”和“块号”组成

4.页表记录进程页面和实际存放的内存块之间的对应关系。

然后这里有个基本地址变换机构,它可以借助进程的页表将逻辑地址转换为物理地址。

通常会在系统中设置一个页表寄存器(PTR),存放页表在内存中的起始地址F和页表长度M,进程为执行时,页表的起始地址和页表长度放在进程控制快(PCB)中,当进程被调度时,操作系统内核会把他们放到页表寄存器当中。

然后我们来看看局部性原理:

10号内存块存放代码,23号代码块存放变量。

时间局部性:如果执行了程序中的某条指令,那么不久后这条指令很有可能再次被执行;如果某个数据被访问过,不就之后该数据很有可能再次被访问。(因为程序中存在大量的循环)

空间局部性:一旦程序访问了某个存户单元,在不久之后,其附近的存储单元也很有可能被访问。(因为很多数据在内存中都是连续存放的)。

时间局部性和空间局部性统称为局部性原理。

比如我们每次都要访问一个逻辑地址都需要查询内存中的页表。由于局部性原理,可能连续多次查到的都是同一个页表。既然如此,能否利用这个特性减少访问页表的次数呢?

所以,有了快表的存在(TLB)

快表,又称联想寄存器(TLB),是一种访问速度比内存块很多的高速缓冲寄存器,用来存放当前访问的若干页表项,以加速地址变换的过程,与此对应,内存中搞得页表常称为慢表。

下面这个图很不错,大家可以好好看看:

大家着重点在块表那里即可。如果大家刷过leetcode的算法题就很容易理解这些东西了。这个快表其实就是一个比内存更快的告诉存储器,存储着最久访问过的页号及其内存块。当你第一次访问时发现快表里没有,就去慢表中找,然后把慢表中的这个页号存储到快表中。等到下次你再访问这个页号的话,就不用去慢表中查找了,直接在快表中查,这样极大的提高了效率。类似于动态规划里面的备忘录算法,用hash ** p存储已经计算过的值,下次需要直接从hash ** p中取出,由于hash ** p的时间复杂度为O(1),所以极大的提高了效率,这里的hash ** p就类似于这里的快表了。

而由于局部性原理,使快表的命中率很高,也就是说很多时候都是从快表中取,而不是从慢表中取。

然后还有两级页表的存在,用于弥补单级页表的缺点,在这里就不细谈了,以后有机会再聊。

讲了那么多的基本分页存储管理,是时候转到基本分段存储管理了。

基本分段存储管理和基本分页存储管理最大的区别就是:离散分配时所分配的地址空间的基本单位不同。

直接来个示意图,让大家都理解:从左到右

相信大家一看就懂了。我们下面来用术语讲:

进程的地址空间:按照程序自身的逻辑关系划分为若干个段,每个段都有一个段名(在低级语言中,程序员使用段名来编程),每段从0开始编址

内存分配规则:以段为单位进行分配,每个段在内存中占据连续空间,但各段之间可以不相邻。

(看完这个我马上想起的是当年用汇编写单片机时,也是使用段名来编程的,一阵心酸泪啊)

由于是按逻辑功能模块划分,用户编程更方便,程序可读性更高。

编译程序时会把段名转化为相应的段号,在执行的时候cpu是根据段号去寻找地址的。

分段系统的逻辑地址结构由段号(段名)和段内地址(段内偏移量)所组成:

段号的位数决定了每个进程最多可以分多少个段。

段内地址位数决定了每个段的最大长度是多少。

比如:

段号占16位,即2的16次方= ** k个段。每个段的长度也是如此。

下面是一般编码方式

内存示意图如下:

大家可能比较难理解,但是如果写过汇编的比较大的工程的话应该就很好理解了。

有了上面的基本概念后,我们接着看:

程序分多个段,各段离散的装入内存,为了保证程序能正常运行,就必须从物理内存中找到各个逻辑段的存放位置,为此,需要为每个进程建立一张段映射表,简称“段表”。(这和我们之前“基本分页存储管理”中的页表是极其相似的)

如下图:

有了前面对页表的理解基础,相信大家一看就明白了。

然后对比一下前面的页表,发现这里多了段长的一列,原来是因为进程的页面和内存的页框大小都是相同的,所以不需要标示出来。而分段存储管理则需要标示,就像连续分配存储管理当中的动态分配存储。

每个段对应一个段表项,其中记录了该段在内存中的起始位置(又称“基址”)和段的长度。

所以,这样对应的地址转换详细大家也都猜的出来了。都是差不多的。然后给下面这个图大家理解:

然后我们进行分段和分页管理的对比:

页是信息的物理单位,分页的主要目的是为了实现离散分配,提高内存利用率。分页仅仅是系统管理上的需要,完全是系统的行为,对用户是不可见的。

段是信息的逻辑单位。分段的主要目的是更好地满足用户需求。一个段通常包含一组属于一个逻辑模块的信息。分段对用户是可见的,用户编程时需要显式地给出段名。

页的大小固定且由系统决定。段的长度却不固定,决定于用户编写的程序。

分页的用户进程地址空间是一维的,程序员只需要给出一个记忆符即可表示一个地址。

分段的用户进程地址空间是二维的,程序员在标识一个地址时,既要给出段名,也要给出段内地址。

然后给个图大家自行理解:

分段比分页更容易实现信息的共享和保护。理解这个的关键在于,分段的话可以直接指示哪个段是可共享的,那么其它进程要共享此段只需要在段表中加个指向即可。而分页是固定大小,不够灵活,这样就会导致可共享和不可共享的的代码在同一页面内,那么由于此页面有不可共享代码,所以不能使此页面共享。

看完前面的分段和分页存储管理,就来看最后一个 “段页式存储管理方式”

看段页式存储管理之前,我们先来分析一下分段和分页的优缺点:

分页管理:

优点:内存空间利用率高,不会产生外部碎片,只会有少量的页内碎片。

缺点:不方便按照逻辑模块实现信息的共享和保护。

分段管理:

优点:很方便按照逻辑模块实现信息的共享和保护

缺点:如果段长过大,为其分配很大的连续空间会很不方便,另外,段式管理会产生外部碎片。(使用“紧凑”技术可以解决但是时间代价太大)

所以,基于上面的原因,就产生了段页式存储管理。

将进程按逻辑模块分段,再将各段分页(如每个页面4KB)

再将内存空间分为大小相同的内存块/页框/物理块

进程前将各页面分别装入各内存块当中。

如下图所示:

所以,段页式的逻辑地址结构由段号,页号,页内偏移量组成。

段号的位数决定了每个进程最多可以分几个段

页号位数决定了每个段最大有多少页

页内偏移量决定了页面大小,内存块大小是多少。

如下图:

段号16位,2的16次方= ** K,所以进程最多 ** K个段。

页号4位,即一个段最多有16个页

页内偏移量为12位,2的12次方=4096=4KB,即页面大小为4KB.

分段对用户是可见的,程序员编程时需要显式地给出段号、段内地址。而将各段“分页”对用户是不可见的。系统会根据段内地址自动划分页号和页内偏移量。

因此,段页式管理的地址结构是二维的。

然后,我们自然而然地讨论到这里的段表和页表:如下图。段表里存放页表,页表映射内存块号。

然后给出最后的运行流程:

和前面的结构都差不多,大家自己领悟即可。

没错,操作系统的内存管理就暂时先学到这里了。。有点多,,慢慢消化。

扫码免费用

源码支持二开

申请免费使用

在线咨询