zoukankan      html  css  js  c++  java
  • 内存分配与内存管理的一些理解

    内存分配方式与内存分配算法

    内存分配方式有两种,连续内存分配方式和离散内存分配方式。不同的分配方式又有不同的分配算法。

    内存分配算法,其实就是:有一大块空闲的资源,如何合理地分配资源?内存分配的思想可以用到很多其他的领域。比如Java虚拟机是如何将内存分配与回收的?再比如文件系统是如何将磁盘块分配与回收的?其本质就是如何把空闲的资源分配出去,分配之后又如何回收?目标就是分配快,回收也快,而且还不浪费。那么,就需要根据资源的特点、以及应用场景做权衡从而选择何种方式进行分配与回收。

    ①连续内存分配方式

    1)固定分区分配

    将内存划分成若干个固定大小的块。将程序装入块中即可。内存划分成各个块之后,块大小不再改变。当然,划分块的方式有:所有的块大小相等;划分的块大小不相等。

    这种方式,在实际的内存分配之前,就已经知道了所有的内存块大小了。

    2)动态分区分配

    需要一个空闲表 或者 空闲链 来记录目前系统中空间的内存区域。在内存分配时,需要查找空间表或空闲链找到一块内存分配给当前进程。

    动态分区分配算法:

    a)首次适应法

    b)循环首次适应法

    c)最佳适应法

    d)最坏适应法

    e)快速适应法

    3)可重定位分区分配

    说白了,就是增加了内存移动的功能。由于若干次内存分配与回收之后,各个空闲的内存块不连续了。通过“重定位”,将已经分配的内存“紧凑”在一块(就类似于JVM垃圾回收中的复制算法)从而空出一大块空闲的内存出来。

    ”紧凑“是需要开销的,比如需要重新计算 地址,这也为什么JVM垃圾回收会导致STW的原因。

    而离散分配方式--不管是分页还是分段,都是直接将程序放到各个离散的页中。从而就不存在“紧凑”一说了。

    连续内存分配方式涉及两种操作:内存分配操作 和 内存回收操作

    ②离散内存分配方式

    内存资源是有限的,程序要运行,必须得加载到内存。如果内存已经满了,而现在又有新的程序要运行,怎么办?---SWAP

    把当前不用的程序(数据)先换出内存,从而就有空间 加载当前需要运行的程序的一部分数据进入内存,这样大大提高了内存的利用率。

    由于牵涉到换入与换出,前面的连续内存分配方式就有点不适用了。因为,最明显的一个问题:对于连续内存分配方式,究竟换出哪部分数据呢?

    而这种只装入部分"数据"就可以使程序运行的机制,就是虚拟存储器的本质。

    1)分页存储管理

    将进程的逻辑地址空间分成若干大小相等的页面;同时,也将物理内存分成相等大小的页面(称为块或frame)。在为进程分配内存时,以块为单位将进程的若干页 可以 装入到内存中多个不邻接的物理块中。

    从上可以看出:“离散” 体现在:进程在内存中分配的空间(物理块)是不连续的。而对于连续分配方式,进程在内存的分配的空间是连续的。

    现在考虑32位系统,每个物理块的大小为4KB。如何把逻辑地址 转换成 物理地址?

    对每个进程而言,都有着自己的页表。页表的本质就是逻辑地址到物理地址的映射。

    分页存储中的逻辑地址的结构如下:

    1)由于进程的逻辑页面大小与物理块(页帧)大小相同,故都为4K,因此需要12个位表示4K的大小(2^12=4K),即图中的【0-11】

    2)【12-31】表示的是页号。一共有20个位表示页号,也即:对于一个进程而言,一共可以有1M(2^20=1M)个页。

    3)每个进程的逻辑地址空间范围为0-2^32-1,因为:每个页大小为4K,一共有1M个页。故进程可用的逻辑空间为2^32B

    逻辑地址到物理地址的转换需要用到页表。具体细节是有一个“地址变换机构”,它有一个寄存器保存页表在内存的起始地址 以及 页表的长度

    上面提到,一个进程最多可以有1M个页,故页表就有1M个页表项。假设每个页表项只有1B,那页表的大小也有1MB,所以:一般而言,页表也是很大的,不能全放在寄存器中,故页表也是存储在内存中的。(有些机器有“快表”,快表就是一个寄存器,它保存了页表中的部分表项);其次,也可以使用多级页表以解决单个页表太大的问题。

    那现在给定一个逻辑地址,怎么知道其物理地址呢?

    ①将【12-31】位的页号与 页表的长度比较。页号不能大于页表长度,否则越界。

    ②根据页号 找到 该页号所在的页表项,即该页号对应着哪个页表项。因为,页表项里面就存放着物理地址。

    那如何查找页表项呢?将页号乘以页表项的长度(每个页表项,其实就是一个逻辑的页 到 物理页 的映射信息),就知道了该逻辑页对应着哪个页表项(根据页号匹配页表项一般是由硬件完成的)

    然后,正如前面提到,页表也是保存在内存中的,故需要页表的内存始址(这是也为什么地址变换机构 保存 页表在内存的起始地址的原因),将页表始址 与 上面的乘积相加,就得到了该逻辑页对应的页表项的物理地址。读这个页表项的物理地址中的内容,就知道了该逻辑页对应的物理块地址(物理地址)。从而,就完成了逻辑地址到物理地址的转换。

    从上面可以看出,CPU每存取一个数据时,需要两次访问主存。一次是访问页表项的物理地址,得到了数据的物理块地址。第二次拿着物理块地址去取数据。

    在分页存储管理方式下:由于取一个数据,需要二次访存,CPU处理速度降低了一半,正由于这个原因:引入了“快表”(又称TLB(Translation Lookaside Buffer)),快表是个寄存器,用来保存那些当前访问过的页表项。从而,读页表项时,不需要再访存了,而是直接从寄存器中读取。

    虚拟存储器

    谈到虚拟存储器,总是说它从逻辑上扩充了内存的容量,why?

    内存是有限的,作业初始时保存在磁盘上的,如果要运行,必须得将相应的程序(数据)加载到内存中。那如果要运行的作业特别多,无法一下子装入内存,怎么办?

    一种方式是加内存条,这是从物理上扩充内存的容量。

    另一种方式是:先把作业的一部分程序(数据)装入内存,先让它运行着,运行过程中发现: 咦,我还需要其他的数据,而这些数据还未装入内存,因此就产生中断(缺页中断)再将数据加载到内存。

    采用这种方式,系统一次就可以将很多作业装入内存运行了。这时,从物理上看,内存还是原来的大小,但是它能运行的作业多了,因此说从逻辑上扩充了内存。

    将虚拟存储器这种思想与分页存储管理结合,一次只将作业的部分页面加载到内存中,形成了一个强大的内存分配与管理系统了。引入了虚拟存储器,同样需要有页表,记录逻辑地址到物理地址的映射,只不过此时的页表更复杂了,因为,有些页可能还在磁盘上。;还需要有缺页中断处理机构,因为毕竟只将一部分数据装入内存,会引起缺页中断嘛,就需要处理中断嘛;还需要地址变换机构,这里的地址变换机构功能更多,因为需要处理中断情况下的地址变换。

    2)分段存储管理

    与分页比较相似,不介绍了。

  • 相关阅读:
    Codeforces 177G2 Fibonacci Strings KMP 矩阵
    Codeforces Gym100187C Very Spacious Office 贪心 堆
    Codeforces 980F Cactus to Tree 仙人掌 Tarjan 树形dp 单调队列
    AtCoder SoundHound Inc. Programming Contest 2018 E + Graph (soundhound2018_summer_qual_e)
    BZOJ3622 已经没有什么好害怕的了 动态规划 容斥原理 组合数学
    NOIP2016提高组Day1T2 天天爱跑步 树链剖分 LCA 倍增 差分
    Codeforces 555C Case of Chocolate 其他
    NOIP2017提高组Day2T3 列队 洛谷P3960 线段树
    NOIP2017提高组Day2T2 宝藏 洛谷P3959 状压dp
    NOIP2017提高组Day1T3 逛公园 洛谷P3953 Tarjan 强连通缩点 SPFA 动态规划 最短路 拓扑序
  • 原文地址:https://www.cnblogs.com/hapjin/p/5689049.html
Copyright © 2011-2022 走看看