1 2 3 4

CSAPP(第三版)第九章虚拟内存学习笔记

虚拟内存是计算机系统最重要的概念之一的原因:

  • 虚拟内存是核心的。
  • 虚拟内存是强大的。
  • 虚拟内存是危险的。

物理和虚拟寻址

计算机系统的主存被组织成一个由M个连续的字节大小的单员组成的数组。每个字节都有一个唯一的物理地址。
image
最早期的PC使用物理寻址,而且诸如数字信号处理器,嵌入式微控制器以及Cray超级计算机这样的系统仍然继续使用这种寻址方式。然而,现代处理器使用的是一种称为虚拟寻址的寻址方式:
image

地址空间

地址空间是一个非负整数地址的有序集合:如果地址空间中的整数是连续的,那么我们说它是一个线性地址空间。

虚拟内存作为缓存的工具

概念上而言,虚拟内存被组织为一个由存放在磁盘上的N个连续的字节大小的单元组成的数组。每个字节都有一个唯一的虚拟地址,作为到数组的索引。磁盘上数组的内容被缓存再主存中。和存储器层次结构中其她缓存一样,磁盘上的数据被分割成块,这些块作为磁盘和主盘之间的传递单元。VM系统通过将虚拟内存分割为称为虚拟页的大小来固定的块来处理这个问题。每个虚拟页的大小为\(P=2^p\)字节。类似地,物理内存被分割为物理页,大小也为P字节呗称为页帧。
image

DRAM缓存的组织结构

为了有助于清晰理解存储层次结构中不同的缓存概念,我们将使用术语SRAM缓存来表示位于CPU和主存之间的L1,L2和L3高速缓存,并且用术语DRAM缓存来表示虚拟内存系统中的缓存,它在主存中缓存虚拟页。

页表

image

页命中

image

缺页

image
image

分配页面

image

又是局部性救了我们

地址翻译

image
image
image
image

结合高速缓存和虚拟内存

主要思路是地址翻译发生在高速缓存查找之前。
image

利用TLB加速地址翻译

image

多级页表

image

综合:端到端的地址翻译

  • TLB是利用VPN的位进行虚拟寻址的
  • 页表是一个单级设计。
  • 高速缓存

案例研究 Inter Core i7/Linux内存系统

Core i7地址翻译

image
image

Linux虚拟内存系统

一个虚拟内存系统要求硬件和内核软件之间的紧密协作。
image
1.Linux虚拟内存区域
linux将粗呢内存组织成一些区域的集合。
image
2.Linux缺页异常处理
1.虚拟地址A是合法的吗?
2.试图进行内存访问是否合法?
3.内核知道缺页是由于对合法的虚拟地址进行合法的操作造成的。
image

内存映射

Linux通过将一个虚拟内存区域与一个磁盘的对象关联起来,以初始化这个虚拟内存区域的内容,这个过程称为内存映射。
虚拟内存区域可以映射到两者弄类型的对象中的一种:
1.Linux文件系统中的普通文件
2.匿名文件

再看共享对象

image

再看fork函数

再看execve函数

假设运行当前进程中的程序执行了如下的execve调用:execve("a.out", NULL, NULL);

  • 删除已存在的用户区域
  • 映射私有区域
  • 映射共享区域
  • 设置程序计数器
    image

使用mmap函数的用户级内存映射

动态内存分配

虽然可以使用低级的mmap和munmap函数来创建和删除虚拟内存的区域,但是C程序员还是会觉得当运行时需要额外虚拟内存时,用动态内存分配器更方便,也有更好的移植性。
image
显式分配器,要求应用显式的释放任何已分配的块。
隐式分配器,另一方面,要求分配器检测一个已分配块何时不再被程序所使用,那么就释放这个块。

为什么要使用动态内存分配

程序员使用动态内存分配的最重要的原因是经常知道程序实际运行时,才知道某些数据结构的大小

分配器的要求和目标

显式分配器必须在一些相当严格的约束条件下工作:

  • 处理任何的请求序列
  • 立即响应请求
  • 只使用堆
  • 对齐块
  • 不膝盖已分配的块

碎片

造成堆利用率很低的主要原因是一种称为碎片的现象,当虽然有未使用的内存但不能用来满足分配请求时,就发生这种现象。有两种形式的碎片:内部碎片和外部碎片。
内部碎片是在一个已分配块比有效载荷大时发生的。
外部碎片是当空闲内存合计起来足够满足一个分配请求,但是没有一个单独的空闲块足够大可以处理这个请求时发生的。

实现问题

  • 空闲块组织
  • 放置
  • 分割
  • 合并

隐式空闲链表

image
image

放置已分配的块

当一个应用请求一个k字节的块时,分配器搜索空闲链表,查找一个足够大可以放置所请求的空间块。分配器执行这种搜索的方式是由防治策略决定的。常见的策略是首次适配,下一次适配和最佳适配。

分割空闲块

image

获取额外的堆内存

如果分配器不能为请求快找到合适的空间块将会发生什么呢?一个选择是通过合并哪些在内存中物理上相邻的空间块来创建一些更大的空闲块。然而,如果这样还是不能生成一个足够大的块,或者如果空间块已经最大程度的合并了,那么分配器就会通过调用sbrk函数,向内核请求额外的堆内存。

合并空闲块

image

带边界标记的合并

image
image

垃圾收集

垃圾收集器是一种动态内存分配器,它自动释放程序不再需要的已分配块

垃圾收集器的基本知识

垃圾收集器将内存视为一张有向法人可达图
image

Mark&Sweep垃圾收集器

Mark&Sweep垃圾回收器由标记阶段和清楚阶段组成。

C程序中常见的与内存有关的错误

间接引用指针

读未初始化的内存

存续栈缓冲区溢出

假设指针和她们指向的对象是相同大小的

造成错位错误

引用指针,而不是它所指向的对象

误解指针运算

引用不存在的变量

引用空闲堆块中的数据

引起内存泄漏

posted @ 2022-09-23 10:28  无序  阅读(82)  评论(0编辑  收藏  举报