操作系统内存管理学习笔记

操作系统内存管理目标

计算机所有的设备和CPU通信都需要经过内存,内存管理的目标包括:

存取速度

cache是一种存储速度比内存快,容量比内存小得多的存储收器。利用cache可以解决快速CPU和慢速内存间矛盾,CPU首先从cache中读取数据,cache miss之后再从内存中读取。cache可以分为三级,前两级集成在CPU核内部,三级缓存位于主板上,由多核共享。

在这里插入图片描述

操作正确

内存正确的分配和回收

地址保护策略

从安全隔离角度考虑,禁止进程访问内核内存空间和其他进程内存空间。操作系统一般不干预CPU对内存的访问,因此这一块功能一般由硬件实现,比如基址寄存器和限长寄存器,前者记录该进程的基址地址、后者记录进程最大可访问的内存长度,这两寄存器的值只能由特权指令加载。进程在调用用户态API时,访存地址须位于上述地址范围内,超过会触发中断,从而进程异常退出。

因为逻辑地址值等于从起始逻辑地址的偏移,等于逻辑地址长度,所以使用逻辑地址和内存限长比较,就可以判断出地址是否越界

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-szNbAIzm-1654440208006)(${img}/image-20220604220320261.png)]

地址转换

实现逻辑地址、物理地址之间的转换

地址空间和地址转换

逻辑地址/相对地址/虚拟地址:面向程序的地址,地址从0开始递增,每条指令的地址就是相对首条地址的偏移。

物理地址/绝对地址:内存单元的实际地址。

逻辑地址空间:逻辑地址的合集

物理地址空间:物理地址的合集

地址转换:CPU操作进程的时候,用的是逻辑地址,逻辑地址经过内存管理单元(MMU)转换成物理地址,转换逻辑是:物理基址+逻辑地址,其中物理基址从页表从获取。

使用逻辑地址的好处

每次加载程序的时候不用修改代码中的地址,只要修改基址就行。

什么时候进行地址转换

程序从代码到进程经过编译–>加载–>运行,三个阶段,如果在编译或加载阶段进行地址转换,程序运行时的地址就确定了,一旦修改程序将无法运行,所以地址转换在运行时最为合适。

进程加载到内存之后的地址还是逻辑地址,执行某一条指令时,如call x,才进行地址转换,转换由MMU进行,物理起始地址记录在基址寄存器(重定位寄存器)中,访问实际地址的时候,只需将物理基址加上逻辑地址,就能得到物理地址。

CPU访问的地址是逻辑地址,物理地址对CPU是不可见的。

在这里插入图片描述

连续的内存分配

操作系统对进程的内存分配具备如下特性:

  • 进程内部的内存是连续的(在不考虑分段和分页的前提下)
  • 进程和进程之间的内存是连续的

内存分配策略

内存分配策略包括固定分区内存分配策略和可变分区内存分配策略,前者是老的操作系统在当时内存小、进程数少的环境下的分配策略,现在已经不用了。

固定分区内存分配策略

操作系统事先将内存分割成大小不同的分区,操作系统根据进程所占内存大小,选择合适的分区,分配给进程。并且维护一个分区表,记录分区的基址、大小、是否已分配。每个分区只能被用于一个进程,用不完的内存不会重新分配,产生碎片。

回收分区的时候,只需要把已分配的标志修改即可。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iyBRhqZT-1654440208006)(${img}/image-20220604221844815.png)]

可变分区内存分配策略

内存按需分配,即进程占多大空间,就从内存中开辟一个相同大小的连续空间给进程。操作系统记录两张表,一张记录可用内存的基址和长度,一张记录已分配表的基址、长度和被哪个进程占用。未被分配的连续内存被称为孔洞,计算机初始情况下只有一个孔洞,大小是整个内存大小,后续不断分配和回收后,形成多个不连续的孔洞集合。

分配策略包括:

  • 首次适应:分配首个满足大小的孔洞,效率高,无需遍历内存
  • 最佳适应:分配最小的满足大小的孔洞,浪费小,需要遍历内存
  • 最坏适应:分配最大的孔洞,孔洞剩余部分最大概率能被利用,需要遍历内存

内存碎片

内存碎片指很小的难以被利用的内存分区。碎片分为:

  • 内部碎片:针对固定分区内存分配策略
  • 外部碎片:针对可变分区内存分配策略,外部碎片可以通过压缩技术优化,

实例

比如一个main函数:

#include <stdio.h>

int
main(int argc, char **argv)
{
        int a = 1 + 1;

        return 0;
}

首先编译成.o文件:

gcc -g -c main5.c

然后反编译成汇编代码:

[root@localhost test]# objdump -d main5.o

main5.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   89 7d ec                mov    %edi,-0x14(%rbp)
   7:   48 89 75 e0             mov    %rsi,-0x20(%rbp)
   b:   c7 45 fc 02 00 00 00    movl   $0x2,-0x4(%rbp)
  12:   b8 00 00 00 00          mov    $0x0,%eax
  17:   5d                      pop    %rbp
  18:   c3                      retq

其中第一列为指令的逻辑地址,第二列为指令码。可以看到地址从0开始,属于逻辑地址,CPU处理的也是逻辑地址,如何转换成物理地址应用程序并不关心。

总结自:
https://www.bilibili.com/video/BV1bf4y147PZ?p=21

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值