内存管理(一)——内存分配

news/2024/11/8 6:40:12/

前言

我们都知道,计算机工作的过程概括起来就是 CPU 去内存中读取指令并执行的过程,但是如果运行我们的程序直接操作物理内存,将会引发很多的问题(比如不同进程之间访问/修改的隔离、权限等等),所以爱操心的操作系统就帮我们实现了内存管理。

暂时可以先简单地理解为操作系统通过虚拟内存技术实现了内存管理,首先抽象出一层虚拟的内存空间,当进程创建时,给每个进程都分配一个虚拟的内存空间,这样程序所使用的地址就是虚拟内存地址,然后实际运行时,再把虚拟地址映射到物理地址,从而给程序分配物理内存地址使用。

这样,在编写程序的时候就可以尽情地使用虚拟地址了,其他的一系列工作都交由操作系统帮我们完成。

操作系统的内存管理需要实现以下几个功能:

  • 地址转换:将程序中的逻辑地址转换成内存中的物理地址(抽象)
  • 存储保护:保证个个作业在自己的内存空间内运行,互不干扰(保护)
  • 内存的分配与回收:当作业或进程创建后系统会为他们分配内存空间,当结束后内存空间也会被回收。
  • 内存空间的扩充:利用虚拟存储技术或自动覆盖技术,从逻辑上扩充内存(虚拟化)
  • 进程间通信(共享)

本文将从分配物理内存开始介绍:

内存分配指的是操作系统将物理内存分配给程序以使用。(和编程语言的分配内存不同,如 C 中的 mallocmmap 等,后续会慢慢讲到的)

分配内存经历了两个发展阶段,一开始是使用连续型分配的方式,后面慢慢发展到了非连续型分配,现代的操作系统基本上都是使用非连续型分配的方式。这里的连续和非连续,指的是分配给程序的物理内存空间是否连续

连续型分配

连续分配方式是最早出现的一种存储器分配方式,分配的策略为一个用户程序分配一个连续的物理内存空间

缺点:

  • 内存利用率低
  • 有外碎片、内碎片的问题

连续型分配有以下四种方式:单一连续分配、固定分区分配、动态分区分配、动态重定位分配。

内存碎片指的是不可用的空闲内存。外部内存碎片指的是未被分配,但是由于太小而无法被分配的内存空间。内部碎片指的是已经被分配,但是未被进程使用的内存空间。

先把内存简单理解为一个大数组,假设把 0~50 分配给了进程A,把 55~100 分配给了进程B,那么 50~55 就是外部碎片。假如进程A实际只用了 40 的空间,那还有 10 就是内部碎片。

单一连续分配

单道程序环境下经常使用的分配方式,将整个内存直接交由一个程序独占,当其他程序需要使用的时候,需要覆盖(Overlay)整个内存,即一次只能运行一个程序。

优点是简单高效,无外部碎片。缺点是可能存在大量内部碎片,内存利用率低,且只能用于单用户。

固定分区分配

是最简单的多道程序存储管理方式,将用户内存空间划分为若干个固定大小(不同分区大小可以不相等),每个分区只装入一道作业。

为便于内存分配,通常将分区按大小排队,并为之建立一张分区使用表,其中各表项包括每个分区的起始地址、大小及状态。

这种方式不会产生外部碎片,但是内部碎片可能较大,也有可能因为程序太大而无法放入任何一个分区。

动态分区分配

动态分区分配又称可变分区分配,不预先划分内存,而是在程序装入内存时,根据进程的大小动态地建立分区,并使得分区的大小正好适合进程的需要,因此系统中分区的大小和数目是可变的。

为了实现动态分区分配,通常有两种方式:空闲分区表和空闲分区链。

这种方式在开始时很好,但是随着时间的推移,内存中会产生越来越多的碎片。

在这里插入图片描述

紧凑

可以通过紧凑技术减少外部碎片。通过移动内存中作业的位置,把原来多个分散的小分区拼接成一个大分区的方法。

系统每紧凑一次,就要对移动了的程序或数据的地址进行修改,这个功能不仅实现复杂,而且还大大地影响到系统的效率。

紧凑分为两种,其中静态重定位是通过软件的方式实现的,也是动态分区分配中所使用的;而动态重定位是结合硬件支持的,是动态重定位分配中所使用的。

  • 静态重定位:在程序装入内存的过程中完成,即在程序运行前,完成程序各个地址的重定位。
  • 动态重定位:在程序运行的过程中完成,需要动态重定位寄存器的支持。
动态分区分配算法

把一个新作业装入内存,需要按照一定的分配算法选出一个分区分配给作业。常见的动态分区分配算法有以下四种:

FF,首次适应算法,First Fit。从空闲分区表的第一个表目起查找该表,把最先能够满足要求的空闲区分配给作业。

NF,循环首次适应算法,Next Fit。从上次找到的空闲分区的下一个空闲分区开始查找,直至找到一个能满足要求的空闲分区。

BF,最佳适应算法,Best Fit。从全部空闲区中找出能满足作业要求的、且大小最小的空闲分区。最小化外部碎片的产生。

WF,最差适应算法,Worst Fit。从全部空闲区中找出能满足作业要求的、且大小最大的空闲分区。避免产生太多微小碎片。

除了这四种最常用的,还有其他的分配算法:

QF,快速适应算法,Quick Fit。将空闲分区按照大小进行分类,并使用链表将同一大小的分区进行连接,然后使用索引表进行管理。

在这里插入图片描述

伙伴系统,buddy system。使用二进制优化的思想,将内存以2的幂为单位进行分配,合并时只能合并是伙伴的内存块。两个内存块是伙伴的三个条件是:

  • 大小相等
  • 地址连续
  • 两个内存块分裂自同一个父块

不同的适应算法在不同的情况下各有优劣。

动态重定位分配

动态重定位分配,是在动态分区分配的基础上,加上硬件的支持,从而实现动态重定位的分配方式。

单纯用软件实现紧凑的效率非常低,需要频繁地移动内存位置,且只有在程序未占用 CPU 时才能移动。

除了软件的方式外,还可以用硬件协助实现。通过在系统中增设一个重定位寄存器,用它来存放程序在内存中的起始地址。程序在执行时,真正访问的内存地址是相对地址与重定位寄存器中的地址相加而形成的。当系统对内存进行了紧凑时,不需对程序做任何修改,只要用该程序在内存的新起始地址去置换原来的起始地址即可。

非连续型分配

非连续型分配有分段分页两种。非连续分配允许一个程序分散地装入到不相邻的物理内存分区中,根据分区的大小是否固定分为分页存储管理方式和分段存储管理方式。非连续型分配是现代操作系统常用的分配方式,比如 Linux 就是结合两种方式的段页式管理。

优点:

  • 更好的内存利用和管理
  • 允许共享代码和数据
  • 支持动态加载和动态链接

缺点:

  • 内存管理的开销大(建立虚拟地址和物理地址之间的转化)

针对分段和分页,后续文章将作详细介绍。

总结

内存分配主要有连续型分配和非连续型分配两种,其中现代操作系统使用的通常为非连续型分配。

连续型分配主要有四种方式,分别为单一连续分配、固定分区分配、动态分区分配、动态重定位分配。

扩展

  1. 程序使用的虚拟内存是否连续?

答:操作系统实际分配给程序的物理内存不一定是连续的,但是程序所使用的虚拟内存是连续的。因为根据 CPU 的工作原理,CPU 需要从 PC 指针(Program Counter,程序计数器,指向下一条指令的地址)读取指令、到执行、再到下一条指令,不断循环。由于 PC 指针是顺序地指向下一个虚拟地址,所以程序所使用地虚拟内存需要是连续的。

  1. 两个不同的程序,能否使用同一个虚拟内存地址?

答:可以。由于操作系统的内存管理,分配给每个进程的虚拟内存都是独立且隔离的。


http://www.ppmy.cn/news/241122.html

相关文章

DDR3地址及容量大小

DDR3 地址线 DDR3为减少地址线,把地址线分为行地址线和列地址线,在硬件上是同一组地址线;地址线和列地址线是分时复用的,即地址要分两次送出,先送出行地址,再送出列地址。 一般来说列地址线是10位&a…

STM32——根据地址计算存储空间的大小

首先要知道 1MB1024KB 1KB1024Byte 1Byte8bit 存储空间大小结束地址-起始地址1(用十进制来算,得到结果的单位是Byte) 十六进制与2进制转换表 十六进制2进制00000100012001030011401005010160110701118100091001A(10&#xf…

STL六大组件之——分配器(内存分配,好深奥的东西)

SGI设计了双层级配置器,第一级配置器直接使用malloc()和free(),第二级配置器则视情况采用不同的策略:当配置区块超过128bytes时,视之为“足够大”,便调用第一级配置器;当配置区小于128bytes时,视…

kmalloc分配大小的限制

原文地址:http://linux.chinaunix.net/techdoc/net/2009/04/28/1109237.shtml #################################################################################################################################### kmalloc是通过cache来实现的, 只不过每次…

采用链接分配方式进行外存分配时,可采用的两种形式及其特点。假定磁盘块大小为4K,对于128G的硬盘,其文件分配表FAT需占用多少存储空间?

采用链接分配方式进行外存分配时,可采用的两种形式及其特点。假定磁盘块大小为4K,对于128G的硬盘,其文件分配表FAT需占用多少存储空间? 隐式链接:除文件的最后一个盘快外,每个盘快中都存有指向下一个盘快的…

内存分配方式

一、内存分配方式 内存分配有三种方式: 1、从静态存储区分配。这种方式是在程序编译的时候已经分配好,并且这块内存在程序的整个运行期间都存在。如全局变量,static变量。 2、在栈上创建。在执行函数的时候,函数内局部变量的存储单…

kmalloc详解与分配大小的限制

kmalloc是通过cache来实现的, 只不过每次kmalloc的大小不同, 因此是从不同的cache中分配: /* include/linux/slab.h */ // 注意kmalloc是在头文件中定义的 static inline void *kmalloc(size_t size, gfp_t flags) {if (__builtin_constant_p(size)) { /*__builtin_constant_p…

java语言中 说明或声明数组时内存大小,说明或声明数组时不分配内存大小,创建数组时分配内存大小。...

试井过程中每一实测的压力、说明产量都不随时间变化的叫()。 或声学制具体规定着() 明数义务教育的主要特点() 组时组《中华人民共和国义务教育法》是哪一年颁布的?() 现代社会的迅速变化,不分以及高新科技的冲击,全世界都在进行着学校教育制…