栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

大话操作系统(5)Linux 内存管理

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

大话操作系统(5)Linux 内存管理

文章目录

Linux 内存管理

Linux 操作系统采⽤了哪种⽅式来管理内存呢?Linux 的虚拟地址空间是如何分布的?总结

Linux 内存管理 Linux 操作系统采⽤了哪种⽅式来管理内存呢?

在回答这个问题前,我们得先看看 Intel 处理器的发展历史。
早期 Intel 的处理器从 80286 开始使⽤的是段式内存管理。但是很快发现,光有段式内存管理⽽没有⻚式内存管理是不够的,这会使它的 X86 系列会失去市场的竞争⼒。因此,在不久以后的 80386 中就实现了对⻚式内存管理。也就是说,80386 除了完成并完善从 80286 开始的段式内存管理的同时还实现了⻚式内存管理。
但是这个 80386 的⻚式内存管理设计时,没有绕开段式内存管理,⽽是建⽴在段式内存管理的基础上,这就意味着,⻚式内存管理的作⽤是在由段式内存管理所映射⽽成的地址上再加上⼀层地址映射。
由于此时由段式内存管理映射⽽成的地址不再是“物理地址”了,Intel 就称之为“线性地址”(也称虚拟地址)。于是,段式内存管理先将逻辑地址映射成线性地址,然后再由⻚式内存管理将线性地址映射成物理地址。


这⾥说明下逻辑地址和线性地址:
程序所使⽤的地址,通常是没被段式内存管理映射的地址,称为逻辑地址;
通过段式内存管理映射的地址,称为线性地址,也叫虚拟地址;

逻辑地址是「段式内存管理」转换前的地址,线性地址则是「⻚式内存管理」转换前的地址。

Linux 内存主要采⽤的是⻚式内存管理,但同时也不可避免地涉及了段机制。

这主要是上⾯ Intel 处理器发展历史导致的,因为 Intel X86 CPU ⼀律对程序中使⽤的地址先进⾏段式映射,然后才能进⾏⻚式映射。既然 CPU 的硬件结构是这样,Linux 内核也只好服从 Intel 的选择。
但是事实上,Linux 内核所采取的办法是使段式映射的过程实际上不起什么作⽤。也就是说,“上有政策,下有对策”,若惹不起就躲着⾛。

Linux 系统中的每个段都是从 0 地址开始的整个 4GB 虚拟空间(32 位环境下),也就是所有的段的起始地址都是⼀样的。这意味着,Linux 系统中的代码,包括操作系统本身的代码和应⽤程序代码,所⾯对的地址空间都是线性地址空间(虚拟地址),这种做法相当于屏蔽了处理器中的逻辑地址概念,段只被⽤于访问控制和内存保护。

Linux 的虚拟地址空间是如何分布的?

在 Linux 操作系统中,虚拟地址空间的内部⼜被分为内核空间和⽤户空间两部分,不同位数的系统,地址空间的范围也不同。⽐如最常⻅的 32 位和 64 位系统,如下所示:

通过这⾥可以看出:
32 位系统的内核空间占⽤ 1G ,位于最⾼处,剩下的 3G 是⽤户空间;
64 位系统的内核空间和⽤户空间都是 128T ,分别占据整个内存空间的最⾼和最低处,剩下的中间部分是未定义的。

再来说说,内核空间与⽤户空间的区别:
进程在⽤户态时,只能访问⽤户空间内存;
只有进⼊内核态后,才可以访问内核空间的内存;

虽然每个进程都各⾃有独⽴的虚拟内存,但是每个虚拟内存中的内核地址,其实关联的都是相同的物理内存。这样,进程切换到内核态后,就可以很⽅便地访问内核空间内存。

接下来,进⼀步了解虚拟空间的划分情况,⽤户空间和内核空间划分的⽅式是不同的,内核空间的分布情况就不多说了。

我们看看⽤户空间分布的情况,以 32 位系统为例,我画了⼀张图来表示它们的关系:

过这张图你可以看到,⽤户空间内存,从低到⾼分别是 7 种不同的内存段:
程序⽂件段,包括⼆进制可执⾏代码;
已初始化数据段,包括静态常量;
未初始化数据段,包括未初始化的静态变量;
堆段,包括动态分配的内存,从低地址开始向上增⻓;
⽂件映射段,包括动态库、共享内存等,从低地址开始向上增⻓(跟硬件和内核版本有关);
栈段,包括局部变量和函数调⽤的上下⽂等。栈的⼤⼩是固定的,⼀般是 8 MB 。当然系统也提供了参数,以便我们⾃定义⼤⼩;

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

总结

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

每个进程都有⾃⼰的虚拟空间,⽽物理内存只有⼀个,所以当启⽤了⼤量的进程,物理内存必然会很紧张,于是操作系统会通过内存交换技术,把不常使⽤的内存暂时存放到硬盘(换出),在需要的时候再装载回物理内存(换⼊)。
那既然有了虚拟地址空间,那必然要把虚拟地址「映射」到物理地址,这个事情通常由操作系统来维护。

那么对于虚拟地址与物理地址的映射关系,可以有分段和分⻚的⽅式,同时两者结合都是可以的。
内存分段是根据程序的逻辑⻆度,分成了栈段、堆段、数据段、代码段等,这样可以分离出不同属性的段,同时是⼀块连续的空间。但是每个段的⼤⼩都不是统⼀的,这就会导致内存碎⽚和内存交换效率低的问题。

于是,就出现了内存分⻚,把虚拟空间和物理空间分成⼤⼩固定的⻚,如在 Linux 系统中,每⼀⻚的⼤⼩为 4KB 。由于分了⻚后,就不会产⽣细⼩的内存碎⽚。同时在内存交换的时候,写⼊硬盘也就⼀个⻚或⼏个⻚,这就⼤⼤提⾼了内存交换的效率。

再来,为了解决简单分⻚产⽣的⻚表过⼤的问题,就有了多级⻚表,它解决了空间上的问题,但这就会导致 CPU 在寻址的过程中,需要有很多层表参与,加⼤了时间上的开销。于是根据程序的局部性原理,在CPU 芯⽚中加⼊了 TLB,负责缓存最近常被访问的⻚表项,⼤⼤提⾼了地址的转换速度。
Linux 系统主要采⽤了分⻚管理,但是由于 Intel 处理器的发展史,Linux 系统⽆法避免分段管理。于是Linux 就把所有段的基地址设为 0 ,也就意味着所有程序的地址空间都是线性地址空间(虚拟地址),相当于屏蔽了 CPU 逻辑地址的概念,所以段只被⽤于访问控制和内存保护。

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

学自小林coding,侵删

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/747048.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号