操作系统的内存管理机制总结

参考链接:https://mp.weixin.qq.com/s/oexktPKDULqcZQeplrFunQ

虚拟内存

对于单片机而言,其 CPU 是直接操作内存的「物理地址
在这里插入图片描述
在这种情况下,要想在内存中同时运行两个程序是不可能的。如果第一个程序在 2000 的位置写入一个新的值,将会擦掉第二个程序存放在相同位置上的所有内容,所以同时运行两个程序是根本行不通的,这两个程序会立刻崩溃

操作系统的解决方式

我们可以把进程所使用的地址「隔离」开来,即让操作系统为每个进程分配独立的一套「虚拟地址」,人人都有,大家自己玩自己的地址就行,互不干涉。但是有个前提每个进程都不能访问物理地址,至于虚拟地址最终怎么落到物理内存里,对进程来说是透明的,操作系统已经把这些都安排的明明白白了

在这里插入图片描述
如果程序要访问虚拟地址的时候,由操作系统转换成不同的物理地址,这样不同的进程运行的时候,写入的是不同的物理地址,这样就不会冲突了

  • 我们程序所使用的内存地址叫做虚拟内存地址(Virtual Memory Address)
  • 实际存在硬件里面的空间地址叫物理内存地址(Physical Memory Address)

在这里插入图片描述
那么操作系统是如何将虚拟地址和物理地址进行映射管理的呢?这就引入了分页分段的概念

内存分段

分段机制下的虚拟地址由两部分组成,段选择子和段内偏移量
在这里插入图片描述

  • 段选择子就保存在段寄存器里面。段选择子里面最重要的是段号,用作段表的索引。段表里面保存的是这个段的基地址、段的界限和特权等级等

我们知道了虚拟地址是通过段表与物理地址进行映射的,分段机制会把程序的虚拟地址分成 4 个段,每个段在段表中有一个项,在这一项找到段的基地址,再加上偏移量,于是就能找到物理内存中的地址,如下图
在这里插入图片描述
如果要访问段 3 中偏移量 500 的虚拟地址,我们可以计算出物理地址为,段 3 基地址 7000 + 偏移量 500 = 7500

这是一种很好的方法,但是还存在一定的问题:

  • 第一个就是内存碎片的问题
  • 第二个就是内存交换的效率低的问题

内存碎片产生的原因

我们来看看这样一个例子。假设有 1G 的物理内存,用户执行了多个程序,其中:

  • 游戏占用了 512MB 内存

  • 浏览器占用了 128MB 内存

  • 音乐占用了 256 MB 内存。

这个时候,如果我们关闭了浏览器,则空闲内存还有 1024 - 512 - 256 = 256MB。

如果这个 256MB 不是连续的,被分成了两段 128 MB 内存,这就会导致没有空间再打开一个 200MB 的程序
在这里插入图片描述
解决方式就是内存交换

可以把音乐程序占用的那 256MB 内存写到硬盘上,然后再从硬盘上读回来到内存里。不过再读回的时候,我们不能装载回原来的位置,而是紧紧跟着那已经被占用了的 512MB 内存后面。这样就能空缺出连续的 256MB 空间,于是新的 200MB 程序就可以装载进来

这个内存交换空间,在 Linux 系统里,也就是我们常看到的 Swap 空间,这块空间是从硬盘划分出来的,用于内存与硬盘的空间交换

内存交换效率低的原因

对于多进程的系统来说,用分段的方式,内存碎片是很容易产生的,产生了内存碎片,那不得不重新 Swap 内存区域,这个过程会产生性能瓶颈

因为硬盘的访问速度要比内存慢太多了,每一次内存交换,我们都需要把一大段连续的内存数据写到硬盘上

所以,如果内存交换的时候,交换的是一个占内存空间很大的程序,这样整个机器都会显得卡顿

为了解决内存分段的内存碎片和内存交换效率低的问题,就出现了内存分页

内存分页

分段的好处就是能产生连续的内存空间,但是会出现内存碎片和内存交换的空间太大的问题。

要解决这些问题,那么就要想出能少出现一些内存碎片的办法。另外,当需要进行内存交换的时候,让需要交换写入或者从磁盘装载的数据更少一点,这样就可以解决问题了。这个办法,也就是内存分页(Paging)

分页是把整个虚拟和物理内存空间切成一段段固定尺寸的大小。这样一个连续并且尺寸固定的内存空间,我们叫页(Page)。在 Linux 下,每一页的大小为 4KB

虚拟地址与物理地址之间通过页表来映射,如下图:
在这里插入图片描述
页表实际上存储在 CPU 的内存管理单元 (MMU) 中,于是 CPU 就可以直接通过 MMU,找出要实际要访问的物理内存地址

而当进程访问的虚拟地址在页表中查不到时,系统会产生一个缺页异常,进入系统内核空间分配物理内存、更新进程页表,最后再返回用户空间,恢复进程的运行

分页是如何解决分段中的内存碎片和内存交换效率低的问题呢?

由于内存空间都是预先划分好的,也就不会像分段会产生间隙非常小的内存,这正是分段会产生内存碎片的原因。而采用了分页,那么释放的内存都是以页为单位释放的,也就不会产生无法给进程使用的小内存

如果内存空间不够,操作系统会把其他正在运行的进程中的「最近没被使用」的内存页面给释放掉,也就是暂时写在硬盘上,称为换出(Swap Out)。一旦需要的时候,再加载进来,称为换入(Swap In)。所以,一次性写入磁盘的也只有少数的一个页或者几个页,不会花太多时间,内存交换的效率就相对比较高

在这里插入图片描述
更进一步地,分页的方式使得我们在加载程序的时候,不再需要一次性都把程序加载到物理内存中。我们完全可以在进行虚拟内存和物理内存的页之间的映射之后,并不真的把页加载到物理内存里,而是只有在程序运行中,需要用到对应虚拟内存页里面的指令和数据时,再加载到物理内存里面去

分页机制下的虚拟地址和物理地址的映射

在分页机制下,虚拟地址分为两部分,页号页内偏移。页号作为页表的索引,页表包含物理页每页所在物理内存基地址,这个基地址与页内偏移的组合就形成了物理内存地址,见下图
在这里插入图片描述
对于一个内存地址转换,其实就是这样三个步骤:

  • 把虚拟内存地址,切分成页号和偏移量;

  • 根据页号,从页表里面,查询对应的物理页号;

  • 直接拿物理页号,加上前面的偏移量,就得到了物理内存地址

在这里插入图片描述

简单分页的缺陷
有空间上的缺陷。

因为操作系统是可以同时运行非常多的进程的,那这不就意味着页表会非常的庞大。

在 32 位的环境下,虚拟地址空间共有 4GB,假设一个页的大小是 4KB(2^12),那么就需要大约 100 万 (2^20) 个页,每个「页表项」需要 4 个字节大小来存储,那么整个 4GB 空间的映射就需要有 4MB 的内存来存储页表

这 4MB 大小的页表,看起来也不是很大。但是要知道每个进程都是有自己的虚拟地址空间的,也就说都有自己的页表

那么,100 个进程的话,就需要 400MB 的内存来存储页表,这是非常大的内存了,更别说 64 位的环境了

多级分页

要解决上面的问题,就需要采用的是一种叫作**多级页表(Multi-Level Page Table)**的解决方案

在前面我们知道了,对于单页表的实现方式,在 32 位和页大小 4KB 的环境下,一个进程的页表需要装下 100 多万个「页表项」,并且每个页表项是占用 4 字节大小的,于是相当于每个页表需占用 4MB 大小的空间

我们把这个 100 多万个「页表项」的单级页表再分页,将页表(一级页表)分为 1024 个页表(二级页表),每个表(二级页表)中包含 1024 个「页表项」,形成二级分页。如下图所示在这里插入图片描述

段页式内存管理

内存分段和内存分页并不是对立的,它们是可以组合起来在同一个系统中使用的,那么组合起来后,通常称为段页式内存管理
在这里插入图片描述
段页式内存管理实现的方式:

  • 先将程序划分为多个有逻辑意义的段,也就是前面提到的分段机制;

  • 接着再把每个段划分为多个页,也就是对分段划分出来的连续空间,再划分固定大小的页;

这样,地址结构就由段号、段内页号和页内位移三部分组成。

用于段页式地址变换的数据结构是每一个程序一张段表,每个段又建立一张页表,段表中的地址是页表的起始地址,而页表中的地址则为某页的物理页号,如图所示:
在这里插入图片描述
段页式地址变换中要得到物理地址须经过三次内存访问:

  • 第一次访问段表,得到页表起始地址;

  • 第二次访问页表,得到物理页号;

  • 第三次将物理页号与页内位移组合,得到物理地址

可用软、硬件相结合的方法实现段页式地址变换,这样虽然增加了硬件成本和系统开销,但提高了内存的利用率

Linux内存管理

Linux 内存主要采用的是页式内存管理,但同时也不可避免地涉及了段机制
Linux 系统中的每个段都是从 0 地址开始的整个 4GB 虚拟空间(32 位环境下),也就是所有的段的起始地址都是一样的。这意味着,Linux 系统中的代码,包括操作系统本身的代码和应用程序代码,所面对的地址空间都是线性地址空间(虚拟地址),这种做法相当于屏蔽了处理器中的逻辑地址概念,段只被用于访问控制和内存保护

Linux内存空间是如何分配的

在 Linux 操作系统中,虚拟地址空间的内部又被分为内核空间****和用户空间两部分,不同位数的系统,地址空间的范围也不同。比如最常见的 32 位和 64 位系统,如下所示:
在这里插入图片描述
通过这里可以看出:

  • 32 位系统的内核空间占用 1G,位于最高处,剩下的 3G 是用户空间;

  • 64 位系统的内核空间和用户空间都是 128T,分别占据整个内存空间的最高和最低处,剩下的中间部分是未定义的。

再来说说,内核空间与用户空间的区别:

  • 进程在用户态时,只能访问用户空间内存;

  • 只有进入内核态后,才可以访问内核空间的内存;

虽然每个进程都各自有独立的虚拟内存,但是每个虚拟内存中的内核地址,其实关联的都是相同的物理内存。这样,进程切换到内核态后,就可以很方便地访问内核空间内存
在这里插入图片描述
接下来,进一步了解虚拟空间的划分情况,用户空间和内核空间划分的方式是不同的,内核空间的分布情况就不多说了。

我们看看用户空间分布的情况,以 32 位系统为例,下面的图来表示它们的关系:
在这里插入图片描述
通过这张图你可以看到,用户空间内存,从低到高分别是 7 种不同的内存段:

  • 程序文件段,包括二进制可执行代码;

  • 已初始化数据段,包括静态常量;

  • 未初始化数据段,包括未初始化的静态变量;

  • 堆段,包括动态分配的内存,从低地址开始向上增长;

  • 文件映射段,包括动态库、共享内存等,从低地址开始向上增长(跟硬件和内核版本有关)

  • 栈段,包括局部变量和函数调用的上下文等。栈的大小是固定的,一般是 8 MB。当然系统也提供了参数,以便我们自定义大小;

在这 7 个内存段中,堆和文件映射段的内存是动态分配的。比如说,使用 C 标准库的 malloc() 或者 mmap() ,就可以分别在堆和文件映射段动态分配内存。

  • 7
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java进程管理系统是一个用于管理操作系统中的进程的软件程序。它提供了一组功能来创建、终止、调度和监视进程。 首先,Java进程管理系统可以创建新的进程。它允许用户使用一些指定的参数和设定来启动新的进程。这些参数可能包括进程的优先级、内存分配、代码路径等。通过Java进程管理系统,用户可以方便地创建并管理多个进程。 其次,Java进程管理系统可以终止进程。在某些情况下,用户可能需要中止正在运行的进程,例如当进程出现错误或者需要释放系统资源时。Java进程管理系统允许用户通过指定进程的标识符或其他特定信息,来终止指定进程。 此外,Java进程管理系统还提供了进程调度功能。它可以基于一些调度算法,如先来先服务(FCFS)、时间片轮转等,来决定进程的执行顺序。用户可以通过Java进程管理系统设置进程的优先级,从而影响进程的调度顺序。 最后,Java进程管理系统可以监视进程的运行状态。它可以提供进程的一些重要信息,如进程的ID、执行状态等。通过Java进程管理系统,用户可以实时监视进程,并及时获得相关信息。 总结而言,Java进程管理系统是一个用于管理操作系统中进程的软件程序。它提供了创建、终止、调度和监视进程的功能。通过Java进程管理系统,用户可以方便地控制和管理进程,并有效地利用系统资源。这种管理系统可以在各种操作系统上运行,并且具有良好的扩展性和灵活性。 ### 回答2: Java进程管理系统是一种基于Java编程语言开发的操作系统实验,用于管理和控制计算机上的进程。该系统主要包含进程创建、进程调度、进程同步和进程通信等功能。 首先,进程创建是指在系统中生成新的进程。Java进程管理系统可以通过调用Java的进程相关类和方法来创建进程,例如使用ProcessBuilder类来创建新的进程对象,并通过该对象执行指定的进程命令。 其次,进程调度是指根据一定的策略和算法,决定哪些进程可以获得执行时间。在Java进程管理系统中,可以通过使用多线程技术来实现进程调度。通过创建不同的线程对象,并分配不同的优先级给每个线程,可以实现简单的进程调度功能。 进程同步是指保证进程按照一定的顺序执行,避免出现竞争条件和进程间的冲突。Java进程管理系统可以使用锁、信号量等同步机制来实现进程同步。通过加锁和解锁等操作,可以控制进程对共享资源的访问,避免数据的不一致性和错误。 最后,进程通信是指进程之间通过一定的方式和机制进行信息交换和共享。Java进程管理系统可以使用Java的线程间通信机制,如共享内存、消息队列、信号量等来实现进程之间的通信。通过共享内存可以实现进程间的数据共享,通过消息队列可以实现进程间的异步通信,通过信号量可以实现进程间的同步通信。 总之,Java进程管理系统可以通过Java编程语言实现进程的创建、调度、同步和通信等功能。它为我们提供了一个实验平台,使我们能够了解和学习操作系统中进程管理的基本原理和机制

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值