`
gaojingsong
  • 浏览: 1181828 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

【内存碎片/内存空洞】

阅读更多

内存碎片/内存空洞

内存碎片: 

程序长时间运行后,由于不停的malloc/free操作,尽管不存在内存泄露,但程序所占用的内存空间越来越大,有时候还会导致malloc申请失败,这就是由于内存碎片所导致。



 

产生原因: 

非mmap申请的内存,其释放,只能从堆顶开始。中间部分的内存即使通过free释放掉,但仍然是被当前程序所占用,并未彻底释放到堆中,无法供其他程序使用。只有堆顶部分内存也释放后,这片区域才能融合成一大片空间。

 

解决方案: 

此问题没有最终的完美的解决方案。

 

尽可能多采用内存空间的复用,减少频繁申请大量小的内存块的操作。

对程序所需要的动态内存进行统一规划。把需要长时间占用的内存的申请操作,在程序刚启动后初始化时进行,把不需要长时间占用的内存的申请操作,后执行。这样堆顶可以尽早释放。 

但要注意的是,内存分配不一定是顺序的,即后来申请的内存地址不一定就比原来的内存地址大,可能用了之前释放的一片区域。

 

 

内存空洞和内存泄漏造成的内存增长是有区别的:

内存泄漏是申请了的内存没有释放,如果你在做多次同样的操作,进程所使用的内存应该保持同样的一个速度进行增长。

内存空洞是申请并释放了的内存由于不处于堆顶无法返还给系统,但是这些内存还是能留给进程自身使用,所以如果你做多次同样的操作,进程所使用的内存应该停留在一个水平线上,不怎么增长,或者增长不多。

程序员可以根据这个现象来判断,你的进程中存在的是内存泄漏还是内存空洞。

在实际情况中,内存空洞的现象并很多,通过我的观察在堆中,更多的是内存的碎片而不是内存空洞。因此程序员对于内存空洞只要了解这个概念,在申请分配内存时,本着就近原则就可以了,需要的时候才分配内存,不需要了立刻释放。不必去严格的追求申请和释放的顺序,也做不到。



 

 

Linux 内核只能通过缩小线性内存区的方式来释放物理内存。

方法一,通过使用系统调用 brk,来改变堆顶地址释放内存。

优点:

算法简单,系统调用少,效率高。

缺点:

堆顶下方的物理页面即使空闲也无法及时释放。

 

 

方法二:,通过将对应堆的线性区拆分,将中间的物理页面释放掉。

优点:

堆顶下方的内存能够得到即使的释放。

缺点:

算法复杂,涉及到线性区的拆分与合并,有可能会导致进程堆段形成多个不连续的小块内存空间,对进程的性能影响较大。

 

综合以上因素,linux 内核选则了通过调整堆顶来扩展和释放内存空间。

它也决定了,只要堆顶部还有内存在使用,堆顶下方不管释放了多少内存都不会被释放,这也就是我们经常所说的内存空洞。

除了通过 brk 扩展堆顶地址外,我们还提到了另外一种内存分配方式mmap。当libc 在处理大块内存分配时,其会调用mmap 来分配一块地址空间;当释放时,直接调用unmmap 释放掉该段内存空间,因此对于这种大块内存分配的申请和释放,就不会存在内存空洞的问题。

你可以通过使用mmap 分配内存的阀值,来减少内存空洞的概率。代价是,可能会使用更多的系统调用,降低进程的性能。

要想消除内存空洞的影响,就要求我们在申请和释放内存时,要严格依照就近原则,最先释放堆顶地址的内存。可控制内存的申请和释放的顺序难度十分的大;另外由于内存碎片的影响,每次申请得到的内存地址都带有一定的随机性,后面申请的内存,并不一定就意味着在

堆顶;这简直是Mission impossible。

做为一个程序员,我很受挫折,我无能为力,我调用 free 都释放内存,可它并不一定会返还到系统中,我无法完全控制我程序的行为,谁又能保证堆顶没有那么一块正在使用的内存呢?这也给很多程序员以藉口,在测试中我们程序内存使用量增长,要求他们去检查时,他们往

往会说,“内存我都释放了,这是内存空洞造成的,我也无能为力。”。老板也无话可说,内存空洞简直成了我们的噩梦。

  • 大小: 12 KB
  • 大小: 63.7 KB
0
0
分享到:
评论

相关推荐

    内存碎片的产生

    内存碎片是计算机系统管理内存时常见的一种问题,它主要分为两种类型:连续碎片和非连续碎片。本篇文章将深入探讨内存碎片的产生机制、影响以及如何通过编程实践来避免和解决这个问题。 首先,我们来理解内存碎片的...

    模拟计算机内存的动态分区

    2. 合并:当相邻的空闲区域在分配后变得连续时,操作系统会将它们合并成一个更大的空闲块,减少内存碎片。 3. 分裂:当一个大空闲块不足以满足新进程的需求,但略大于需求时,系统可能需要将该大块分割成两部分,一...

    动态内存分区管理源码

    3. **内存碎片处理**:`setfree`函数通过合并空闲节点来减少内存碎片,这对于提高内存使用效率至关重要。 4. **状态标记**:通过`state`变量标记内存的使用状态,是动态内存管理中常见的一种机制,它帮助系统快速...

    存储卡和RAM碎片整理软件

    当一个文件被创建、修改或删除时,存储空间可能会留下空洞,新文件就可能被分割并存储在这些不连续的位置,形成碎片。这不仅可能导致文件读取速度变慢,还可能浪费存储空间。 存储卡,尤其是经常进行写入操作的SD卡...

    Linux操作系统的内存使用方法详细解析

    然而,有一个问题叫做内存空洞:如果堆顶的内存仍在使用,即使堆底有大量已释放的连续内存,这部分内存也无法被释放,因为它依赖于堆顶指针的下降。由于内核仅能通过调整堆顶指针来管理内存,因此只要堆顶不变,内存...

    易语言源码易语言Asm检测内存源码.rar

    它包括查找内存中的错误、空洞、碎片等。在编程中,内存检测通常用于调试阶段,以确保程序在运行时不会因为内存问题导致崩溃或数据错误。内存检测可以通过读取和分析内存内容来实现,这往往需要对计算机内存管理机制...

    伙伴系统Buddy System 内存管理

    《伙伴系统Buddy System在内存管理中的应用》 伙伴系统(Buddy System)是一种高效的内存管理算法,广泛应用于Unix和...它在保持内存利用率的同时,减少了内存碎片,为操作系统提供了更稳定、更优化的内存分配策略。

    计算机操作系统内存分配实验报告记录.doc

    首次适应算法倾向于使用最先找到的合适空闲分区,避免了在内存低址部分形成大的空洞;最佳适应算法寻找最小的空闲分区,以最大化保留大块连续空间;而最差适应算法则选择最大的空闲分区,可能导致频繁的小分区分配,...

    操作系统-可变分区分配

    现代操作系统中,为了进一步优化内存管理,通常会结合页式或段式虚拟内存系统,将物理内存与虚拟内存相结合,通过页面交换技术解决内存不足的问题,同时也降低了内存碎片的影响。 综上所述,可变分区分配是操作系统...

    3_4.rar_3_4

    3. 内存碎片:分析和处理由于多次分配和释放导致的内存碎片问题。 对于分页式内存管理,我们需要实现以下功能: 1. 页表:创建并维护页表,记录每个逻辑页与物理页的映射。 2. 地址转换:实现逻辑地址到物理地址的...

    存储管理实验报告.doc

    代码中定义了一个名为`hole`的结构体来表示内存空洞,以及`hole_head`链表来跟踪这些空洞。`alloc_mem`函数是进行内存分配的关键,学生需要在这个函数中实现新算法的逻辑。 7. **内存分配流程**: 实验中提到的...

    fastdb-3.05.tar.gz_fastdb_内存数据库

    - 数据结构优化:FastDB采用紧凑的数据结构,减少了内存中的空洞和碎片,以提高内存利用率。 - 高并发支持:FastDB通过事务管理机制保证了多线程环境下的数据一致性,确保高并发场景下的稳定运行。 - 自动内存...

    Marcin_SCHOLKE_defragmentation.zip

    但若数组是引用类型,其内部引用的对象可能会产生内存碎片,这需要对对象而非数组本身进行整理。 3. **DefragmentationTest_Marcin_SCHOLKE.cs**:这个文件可能是测试代码,用于验证碎片整理算法的效果。通常包括...

    动态分区存储管理方式的主存分配回收

    动态分区的主要任务包括:内存分配、内存释放和内存碎片整理。 首先,内存分配涉及为新创建的进程寻找合适的空闲分区。常见的分配算法有首次适应(First Fit)、最佳适应(Best Fit)和最差适应(Worst Fit)。首次...

    湖南大学操作系统作业(5)终稿.pdf

    首次适应算法从内存空间的开头开始查找,找到第一个足够大的空闲区分配给进程,这样可以避免在内存的高端形成大空洞。最佳适应算法遍历所有空闲区,选择最小的超过进程需求的空闲区进行分配,旨在最小化内部碎片。...

    linux环境下一个简单的malloc实现

    - **内存碎片**:连续的内存块因多次分配和释放可能会产生空洞,导致内存利用率降低,这是`malloc`需要解决的问题之一。 2. **简单的`malloc`实现**: - 自定义的`malloc`通常会维护一个内存池,初始化时分配一大...

    试验三:存储管理----可变分区.doc

    最佳适应算法是一种内存分配策略,它在分配内存时倾向于选择最小的空闲分区,以减少内存碎片的产生。在代码中,`allocate()`函数负责执行这个任务,它会遍历空闲区表找到大于请求大小的最小空闲分区。如果找到的空闲...

    c语言实现可变分区的模拟(最佳适应算法)

    总结来说,本项目通过C语言实现了可变分区的模拟,具体采用了最佳适应算法,旨在优化内存分配,尽量减少内存碎片。通过分析和实现这个过程,我们可以更好地掌握内存管理策略,并提高解决实际问题的能力。

Global site tag (gtag.js) - Google Analytics