内存碎片的由来

     经常看别人博客说到“内存碎片”这个概念,而且很多编程技巧书也经常提到频繁地调用内存分配函数会导致越来越多的内存碎片产生,降低内存的利用率。那么这个“内存碎片”究竟是怎么产生的呢?答案可能要从“操作系统”中查找了。

    在翻阅了一些《操作系统》的书之后,对于这个概念有了更清晰的理解,下面进行总结:

       当我们运行一个程序时,处理器要生成一个进程,并把程序载入内存。那么内存是如何分区的呢?是分成固定大小的一块一块么?的确存在这种设计方案,那么我们看看针对这种情况,碎片会出现在哪里?假设我们的一个分区是8M,我们的进程大小是3M,那么当我们的进程装入分区后,分区里面剩余的5M我们并没有用到,而且由于这个分区其他进程也不能同时使用,所以这5M就被浪费了,这种浪费其实就是“碎片”,由于这种碎片出现在分区内,一般我们称它为“内部碎片”。那么我们是否可以使用大小不同的分区呢?比如分区大小从小到大排列 2M、4M、6M、8M、10M。这种方案会缓解这个问题,但并不能完全解决。

      那么是否有其他方案可供我们选择呢?我们是不是可以尝试动态分区,我们的进程有多大,分区大小就为多大。这种方案当然也存在,假设我们先装入一个进程1:20M,然后再装入进程2:14M,再装入一个进程3:18M。接下来进程2运行结束被换出,接着运行一个进程4:8M。现在加入我们要继续装入一个大小为9M的进程的话,会发现已经没有空闲间隙给我们。可实际上内存还留有10M的空间,只是它们并没有连续。所以我们现在遇到了空间还够却无法装入进程的窘境。那些空隙我们就可以称为“外部碎片”,也就是说采用动态分区的方案会产生“外部碎片”。

那么有方法可以克服外部碎片的技术么?“压缩”  听名字你大概能猜出来,压缩其实就是将那边不连续存储的进程压到一起,这样那些中间的空隙也就是外部碎片就消失了。但是压缩是十分耗时间的,同时压缩之后进程的位置也发生了改变,所以我们要求如果支持压缩操作的话,则进程必须得是可动态重定位的(只有当我们访问到某个变量时,才去计算绝对地址)。也就是说装载程序时,程序内访问内存的方式不能是绝对寻址,而是相对定位的,比如说我们的变量只保存相对地址,等到程序实际运行时获得实际地址时,变量再针对这个相对地址得到实际地址。

    绝对加载:加载的地址提前就得要确定,比如变量使用的是内存的物理地址。

    缺点:当我们多个程序共享内存时,无法确定哪块区域一定是留给你用的。

   可重定位加载:我们只是用相对地址来定位,而最终的定位则留到装载时,等到操作系统分配你实际物理地址后再根据这个相对地址得到实际物理地址。

   缺点:由于进程会换入换出。所以实际地址如果在加载时确定了,进程在换入换出之后,放的位置可能与加载时的位置不一致了。

 动态运行时加载:使用相对地址进行定位,而最终的定位则等到执行到该指令时才计算绝对地址。

由于内存压缩十分耗时,,因而操作系统需要巧妙地把进程分配到内存中,以便盖住那些“空隙”。一般来说有三种放置算法:

    1.最佳适配:找到最接近进程大小的空隙

    2.首次适配:从头开始找第一个可以放下进程的空隙

    3.下次适配:从上次找到的空隙往后找可以放下进程的空隙

首次适配一般的结果是最好最优的,下次适配会使得存储空间末尾的最大空闲存储块很快分裂为小碎块,因此使用下次匹配可能会使得更多次的压缩。最佳适配尽管每次都能找到最匹配空间的空隙,但性能太差,类似顺序遍历查找最大值最小值的算法是O(n)的效率一样,平均要扫描整个内存块。

分页

      大小不等的固定分区和大小可变的分区技术在内存上的使用都是低效的,前者会产生内部碎片,后者会产生外部碎片。如果我们采用分页技术,将进程分为固定大小的块,将内存也分为固定大小的块。那么进程的一块可以称为“页”,内存中的一块可以称为可以称为“页框”。一般来说每一页是4K的样子,使用分页技术我们每个进程浪费的空间最多就是进程最后一页的一小部分。很小的内部碎片,但是没有外部碎片。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值