当前位置:柔美女性网 >

绿色生活 >心理 >

c++内存碎片解决方法

c++内存碎片解决方法

c++内存碎片解决方法

1>少用动态内存分配的函数(尽量使用栈空间)

  2>分配内存和释放的内存尽量在同一个函数中(避免内存泄漏)

 3>尽量一次性申请较大的内存2的指数次幂大小的内存空间,而不要反复申请小内存(少进行内存的分割)

  4>使用内存池来减少使用堆内存引起的内存碎片

  5>尽可能少地申请空间

  6>尽量少使用堆上的内存空间~

  7>做内存池,也就是自己一次申请一块足够大的空间,然后自己来管理,用于大量频繁地new/delete操作。

c++内存碎片解决方法

内存问题一直以来都是C/C++开发中比较麻烦的问题,总的来讲,可以分成内存碎片、内存泄漏和内存越界这几类其中,以内存越界最为复杂,而且难以定位。下面我们将通过技术手段逐一分析并解决这三个问题。

一、操作系统的内存管理

进程的虚拟内存空间是地址是连续的,整个内存空间以页为单位进行划分,并不是每个页当前都映射了物理地址(commited),应用程序通过操作系统提供的API对内存进行管理,以页为单位,将虚拟内存地址映射到物理地址或者解除虚拟地址和物理地址的映射,某些情况下操作系统也会自动进行这个过程:例如当物理内存不足时,会根据一定的策略将部分虚拟空间的数据保存到硬盘上,同时解除虚拟空间和物理地址的映射,把空出来的物理地址映射到当前cpu需要访问的虚拟空间(拆东墙补西墙)。

一、内存碎片

当应用程序通过操作系统提供的API动态的申请内存和归还内存,那么难以避免的就会造成当前已分配的内存在进程中占用着不连续的虚拟空间,反过来,不被应用程序占用的空闲内存空间也是不连续的,那么即便这些空闲内存的总量大于下次应用程序申请的空间大小,因为不连续,所以也无法成功申请到。空闲内存不连续的问题越严重(不连续的内存快越多,每块内存越小),分配不成功的概率就越大。

我们通过以下几个技术手段解决这个问题:

1、 建立小内存池机制,相同大小或者大小接近的内存都放到同一个内存池,这样从内存池的每个内存块之间浪费的内存会非常小或者没有浪费。

2、内存池向系统申请内存时都以页为单位进行申请大块内存(Block),内存池对外分配内存也以优先使用使用率最高的Block,这样会有更高的概率将整个Block归还系统。

二、内存泄漏

内存泄漏产生的原因比较简单明确,就是申请的内存已经不需要再次被使用了,但是并没有归还给内存分配器(管理器)或者系统。正确的使用智能指针可以有效的避免内存泄漏的发生,这是推荐的方式。我们下面介绍另外一种在X86下解决内存泄漏的方式。

我们在每次进行内存分配的时候将调用的堆栈记录下来,并且和分配的内存块进行关联,这样,分配的每一块内存都有一个明确的来源,这样我们可以随时统计哪些地方分配了多少内存(内存快照)。我们可以在需要时生成一个内存快照,通过对比内存快照可以确定这段时间内哪些地方分配或者释放了多少内存。

三、内存越界

内存越界是比较难以定位,并且也是非常危险的一个问题。内存越界通常发生的场景有(不限于以下):

1、读写超出内存的有效范围,例如数组下标越界,指针加减运算错误

2、已释放的内存,其指针仍然被某些地方非法持有(野指针),并且进行了读或者写

内存越界读产生的危险总体而言要小于越界写。因为数据读错了,很大概率会立刻暴露问题,比较容易定位,但是越界写的话,很有可能会在后续某个完全不相干的位置或者时间里出现问题,这时已经很难再找回之前写坏数据的现场了。下面我们讨论一种定位内存越界写的方案。

内存越界写主要的问题是往往写的时候没有引发异常,如果我们能在越界写的时候让程序抛出异常,那么这个问题基本就定位了。为此,我们可以令内存分配器每次分配都返回一个永远不重复的地址,这个地址指向的内存前面和后面的一页或者几页的地址空间都是没有映射到物理内存的,那么当对这块内存的读写超出边界的时候就会触发暴力读写的异常。同样,当这块内存被释放以后,我们将这块内存所指向的虚拟地址和物理地址的映射解除,那么后续尝试对这个地址进行读写的时候也会触发暴力读写的异常,这样我们就可以快速定位问题所在。

标签: 碎片 内存
  • 文章版权属于文章作者所有,转载请注明 https://rmnxw.com/lvse/xinli/721pzj.html