- 怎样避免空间碎片而且高效的分配空间
现在普遍采用的段页式内存分配方式就是将进程的内存区域分为不同的段,然后将每一段由多个固定大小的页组成。通过页表机制,使段内的页可以不必连续处于同一内存区域,从而减少了外部碎片,然而同一页内仍然可能存在少量的内部碎片,只是一页的内存空间本就较小,从而使可能存在的内部碎片也较少。
可以采用段页式内存管理
我们对1G的内存进行管理,假如以2M为基本分配空间,那么1G的内存就可以分为512块基本空间,假如数据小于2M空间,再对2M空间进行分配,释放空间时以2M为单位进行释放,从而有效的避免空间碎片的存在,把每片2M空间加入链表,每块的地址都进行集中管理,而且每片空间因为加入了链表,对于不连续的地址也可以进行分配,实现了高效的分配空间和避免空间碎片。
//申请一块2M空间 (void *prt = malloc(2M))
Struct memblock{
Void *ptr;
Int size; //空间大小
Struct memblock *next // 尾指针,加入链表
Int status; //空间使用状态(使用/未使用)
}

二、 减少内存碎片
内存碎,片是因为在分配一个内存块后,使之空闲,但不将空闲内存归还给最大内存块而产生的。最后这一步很关键。如果内存分配程序
是有效的,就不能阻止系统分配内存块并使之空闲。即使一个内存分配程序不能保证返回的内存能与最大内存块相连接(这种方法可以彻底
避免内存碎片问题),但你可以设法控制并限制内存碎片。所有这些作法涉及到内存块的分割。每当系统减少被分割内存块的数量,确保被
分割内存块尽可能大时,你就会有所改进。
这样做的目的是尽可能多次反复使用内存块,而不要每次都对内存块进行分割,以正好符合请求的存储量。分割内存块会产生大量的小
内存碎片,犹如一堆散沙。以后很难把这些散沙与其余内存结合起来。比较好的办法是让每个内存块中都留有一些未用的字节。留有多少字
节应看系统要在多大程度.上避免内存碎片。对小型系统来说,增加几个字节的内部碎片是朝正确方向迈出的- -步。当系统请求1字节内存
时,你分配的存储量取决于系统的工作状态。
如果系统分配的内存存储量的主要部分是1 ~ 16字节,则为小内存也分配16字节是明智的。只要限制可以分配的最大内存块,你就
能够获得较大的节约效果。但是,这种方法的缺点是,系统会不断地尝试分配大于极限的内存块,这使系统可能会停止工作。减少最大和最
小内存块存储量之间内存存储量的数量也是有用的。采用按对数增大的内存块存储量可以避免大量的碎片。例如,每个存储量可能都比前一
个存储量大20%。在嵌入式系统中采用"一种存储量符合所有需要"对于嵌入式系统中的内存分配程序来说可能是不切实际的。这种方法从内
部碎片来看是代价极高的,但系统可以彻底避免外部碎片,达到支持的最大存储量。.
将相邻空闲内存块连接起来是一- -种可以显著减少内存碎片的技术。如果没有这一方法,某些分配算法(如最先适合算法)将根本无法工
作。然而,效果是有限的,将邻近内存块连接起来只能缓解由于分配算法引起的问题,而无法解决根本问题。而且,当内存块存储量有限
时,相邻内存块连接可能很难实现。
有些内存分配器很先进,可以在运行时收集有 关某个系统的分配习惯的统计数据,然后, 按存储量将所有的内存分配进行分类,例如分
为小、中和大三类。系统将每次分配指向被管理内存的一个区域,因为该区域包括这样的内存块存储量。较小存储量是根据较大存储量分配
的。这种方案是最先适合算法和一组有限的固定存储量算法的一种有趣的混合,但不是实时的。
有效地利用暂时的局限性通常是很困难的,但值得一提的是,在内存中暂时扩展共处一地的分配程序更容易产生内存碎片。尽管其它技
术可以减轻这一问题,但限制不同存储量内存块的数目仍是减少内存碎片的主要方法。
现代软件环境业已实现各种避免内存碎片的工具。例如,专为分布式高可用性容错系统开发的OSE实时操作系统可提供三V N 扁
存分配程序:内核alloc(), 它根据系统或内存块池来分配;堆malloc(),根据程序堆来分配,OSE 内存管理程序alloc_ region, 它根据内存
管理程序内存来分配。
从许多方面来看,Alloc就是终极内存 分配程序。它产生的内存碎片很少,速度很快,并有判定功能。你可以调整甚至去掉内存碎片。
只是在分配- -个存储量后,使之空闲,但不再分配时,才会产生外部碎片。内部碎片会不断产生,但对某个给定的系统和/ \种存储量来说是
恒定不变的。
Alloc是一种有八个自由表的固定存储量内存分配程序的实现方法。系统程序员可以对每- -种存储量进行配置,并可决定采用更少的存
储量来进一步减少碎片。 除开始时以外,分配内存块和使内存块空闲都是恒定时间操作。首先,系统必须对请求的存储量四舍五入到下一个
可用存储量。就) \种存储量而言,这一目标可用三个如果语句来实现。其次,系统总是在八个自由表的表头插入或删除内存块。开始时,
分配未使用的内存要多花几个周期的时间,但速度仍然极快,而且所花时间恒定不变。
堆malloc()的内存开销(8 ~ 16字节/分配)比alloc小,所以你可以停用内存的专用权。malloc() 分配程序平均来讲是相当快的。它的
内部碎片比alloc()少,但外部碎片则比alloc()多。它有一个最大分配存储量,但对大多数系统来说,这一-极限 值足够大。可选的共享所有权
与低开销使malloc() 适用于有许多小型对象和共享对象的C++应用程序。堆是一种具有内部堆数据结构的伙伴系统的实现方法。在OSE
中,有28个不同的存储量可供使用,每种存储量都是前两种存储量之和,于是形成-一个斐波那契 (Fibonacci) 序列。实际内存块存储量为
序列数乘以16字节,其中包括分配程序开销或者8字节/分配(在文件和行信息启用的情况下为16字节)。
当你很少需要大块内存时,则OSE内存管理程序最适用。典型的系统要把存储空间分配给整个系统、堆或库。在有MMU的系统中,有
些实现方法使用MMU的转换功能来显著降低甚至消除内存碎片。在其他情况下,OSE内存管理程序会产生非常多的碎片。它没有最大分配
存储量,而且是一种最先适合内存分配程序的实现方法。内存分配被四舍五入到页面的偶数一典型值是 4k字节。s (T111)