跟我学C++中级篇——内存碎片

一、介绍

内存问题是一个经典的“老生常谈”的问题,而且几乎是绕不开的问题。它从科班的书本到小白的学习直到实践工程中,这个问题都是一个经典的技术话题,可以反复的拉出来进行讨论。
换句话说,对于一个开发者来说,从学习书本到实践练习到真正到工程实践中。这个问题会一直如影随形的伴随着开发者,无论是大小工程,只能防范,却不可能完全避免。

二、内存碎片

内存碎片,Memory Fragmentation。所谓内存碎片就是在实际应用中一种内存浪费的现象即在内存中出现了很多无利被使用的小的内存。从而降低了内存应用的效率,进而有可能降低整体程序的性能。
对于实际的应用中,目前内存的处理有多种情况,但不管是开发者手动管理还是自带垃圾回收机制。上层应用内存的分配、应用和回收面对的是操作系统而非硬件本身。这就引入了一个中间层,它引入了安全方便的操作,但也带来了内存碎片的副作用。

三、内存碎片的种类

内存碎片根据其位置和产生的原因,可以划分为两类:内部碎片(Internal Fragmentation)和外部碎片(External Fragmentation)。
内部碎片是指按要求从操作系统分配的内存,有一些内存空间未能使用,但这些空间也无法为自己或其它进程使用。外部碎片更容易理解,它一般指进程反复申请分配和回收内存后,在内存中产生了许多空间很小且不连续的空间区域。虽然从总量上看,这些未使用内存不小,但在实际分配中却无法分配的情况。
一般来说,外部碎片比内部碎片更贴近于开发者理解的内存碎片,但其实二者同样都会导致内存的浪费。

四、内存碎片的影响

内存碎片作为一种在开发经常遇到的问题,它的影响其实非常大。这个在前面分配内存泄露时,已经进行过说明了。此处重点说明一下内存碎片可能导致的后果:

  1. 影响性能
    大量的内存碎片存在导致可用内存的减少,可能产生内存交换和分配速度变慢,导致系统性能的下降
  2. 影响内存利用
    内存碎片的存在,在外部看起来可能内存还很多,但实际大多已经不可用。即明面上的可用内存比实际可用的要大很多。降低了内存的利用率
  3. 影响程序稳定性
    内存碎片的出现,特别是大量累积时,往往可能导致进程在运行过程中无法正常分配内存,轻则不能正常运行,重则直接崩溃
  4. 影响功耗
    对于手动管理内存还好一些,对于那些自动回收内存垃圾的系统,往往频繁的引起回收的动作,增加功耗甚至有可能影响内存的寿命

其实对于内存碎片来说,如果不是服务端运行的程序或者一些特殊情况。大多数情况来说,虽然有危险,但可能没有想象的那么厉害。但还是要加强重视,防止在关键时刻掉链子。

五、分析

大家都知道,操作系统中也是通过虚拟内存与物理内存的映射进行处理的。所谓的内存碎片其实指的就是为了能够更好的平衡物理内存和虚拟内存的利用率和性能之间的一种内存管理机制的产物。
这就需要回想一下虚拟内存的管理机制,段和页(具体的细节如果不明白,可回头补一下相关的操作系统中的知识)。比如为了提高访问效率,分配时需要内存对齐,这就可能分配的内存比实际需要的内存要大,或者上层应用者自行编写了内存池,对于小内存使用时直接分配了一块,其中也有可能导致一部分内存浪费,这其实都是内部碎片的产生原因。如果有操作系统或库相关的内存管理机制,就会发现其实其内部也是使用了一系列的自定义的内存池。其本质是固定大小内存的管理简便和应用效率的一种代价。
另外,在使用内存动态分配时,进程反复的分配回收大小不同的较小的内存,整块的内存被反复分割隔离最后形成了N多无法连续的小内存。或者由于使用了一些不正确的内存分配算法(best fit),导致大量的小内存的碎片。它也能体现出内存问题往往是一个累积的过程,而不是一个简单的大小问题。
在掌握了内存碎片产生的机制和内部原理后,其实就可以有针对性的进行处理,有效防止内存碎片产生。需要说明的是,内部碎片和外部碎片并不是互斥存在的,它们很可能同时存在于系统中。而且它们二者很可能互相影响,即一方的减少有可能引起另一方的增加。故而在实际的开发中,要有针对性的根据需求进行取舍,不能盲目的追求绝对的消除内存碎片。

六、如何避免内存碎片

针对内存碎片的两种情况,可以分别的进行处理,主要有以下的方式:

  1. 内部碎片
    不再使用固定大小的内存分配而采用动态大小的分配,或者采用Linux中的Slab分配方式;也可以减少内存分配的粒度,尽量避免内存的对齐。但这样的后果可能是效率的下降并引入复杂性和外部碎片
  2. 外部碎片
    外部碎片则可以使用固定的分配机制,如分页、分段等或使用内存池。另外尽量使用一次分配,多次使用将内存控制在连续的空间中。当然也可以引入Linux中的伙伴分配系统(Buddy System)并引入一些优化的相关算法如Worst Fit或内存压缩等。但同样,这可能引入内部碎片

对于内存碎片的处理,在现代的软件工程都有针对性的解决办法。但实际的项目中,仍然无法从根本上解决内存碎片的问题。这就是一个典型的现象,理论和实践往往无法达到想象中的适配。理论是固定的,工程是变化的,没有任何一种机制可以将二者完全契合。

七、总结

内存问题表现在实践工程中往往是动态变化的,但其实底层的问题原理却已经清清楚楚。开发者需要掌握的就是将二者在运行中结合起来,能将实际的工程问题转化为技术原理,从而能够迅速的定位并解决。内存碎片其实就是一个典型的实际应用的案例。

最后,推荐一个AI神器,解放我们的双手:
https://mp.csdn.net/vip?utm_source=fx-blog-fpcc

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值