分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

大内高手—内存管理器

转载时请注明出处和作者联系方式:http://blog.csdn.net/absurd

作者联系方式:李先静 <xianjimli at hotmail dot com>

更新时间:2007-7-9

作为一个C程序员,每天都在和malloc/free/calloc/realloc系列函数打交道。也许和它们混得太熟了,反而忽略了它们的存在,甚至有了三五年的交情,仍然对它们的实现一无所知。相反,一些好奇心未泯的新手,对它们的实现有着浓厚的兴趣。当初正是一个新同事的问题,促使我去研究内存管理算法的实现。

内存管理算法多少有些神秘,我们很少想着去实现自己的内存管理算法,这也难怪:有这样需求的情况并不多。其实,至于内存分配算法的实现,说简单也简单,说复杂也复杂。要写一个简单的,或许半天时间就可以搞掂,而要写一个真正实用的,可能要花上你几周甚至几个月的时间。

malloc和free是两个核心函数,而calloc和realloc之所以存在,完全是为了提高效率的缘故。否则完全可以用malloc和free的组合来模拟它们。

拿calloc函数的实现来说,在32位机上,内存管理器保证内存至少是4字节对齐的,其长度也会扩展到能被4字节整除,那么其清零算法就可以优化。可以一次清零4个字节,这大大提高清零速度。

拿realloc函数的实现来说,如果realloc的指针后面有足够的空间,内存管理器可以直接扩展其大小,而无须拷贝原有内容。当然,新大小比原来还小时,更不拷贝了。相反,通过malloc和free来实现realloc时,两种情况下都要拷贝,效率自然会低不少。

另外还有两个非机标准的,但很常用的函数,也涉及到内存分配:strdup和strndup。这两个函数在linux和win32下都支持,非常方便。这完全可以用malloc来模拟,而且没有性能上的损失。

这里我们主要关注malloc和free两个函数的实现,并以glibc 2.3.5(32位linux) 为例分析。

内存管理器的目标

内存管理器为什么难写?在设计内存管理算法时,要考虑什么因素?管理内存这是内存管理器的功能需求。正如设计其它软件一样,质量需求一样占有重要的地位。分析内存管理算法之前,我们先看看对内存管理算法的质量需求有哪些:

l         最大化兼容性

要实现内存管理器时,先要定义出分配器的接口函数。接口函数没有必要标新立异,而是要遵循现有标准(如POSIX或者Win32),让使用者可以平滑的过度到新的内存管理器上。

l         最大化可移植性

通常情况下,内存管理器要向OS申请内存,然后进行二次分配。所以,在适当的时候要扩展内存或释放多余的内存,这要调用OS提供的函数才行。OS提供的函数则是因平台而异,尽量抽象出平台相关的代码,保证内存管理器的可移植性。

l         浪费最小的空间

内存管理器要管理内存,必然要使用自己一些数据结构,这些数据结构本身也要占内存空间。在用户眼中,这些内存空间毫无疑问是浪费掉了,如果浪费在内存管理器身的内存太多,显然是不可以接受的。

内存碎片也是浪费空间的罪魁祸首,若内存管理器中有大量的内存碎片,它们是一些不连续的小块内存,它们总量可能很大,但无法使用,这也是不可以接受的。

l         最快的速度

内存分配/释放是常用的操作。按着2/8原则,常用的操作就是性能热点,热点函数的性能对系统的整体性能尤为重要。

l         最大化可调性(以适应于不同的情况)

内存管理算法设计的难点就在于要适应用不同的情况。事实上,如果缺乏应用的上下文,是无法评估内存管理算法的好坏的。可以说在任何情况下,专用算法都比通用算法在时/空性能上的表现更优。

为每种情况都写一套内存管理算法,显然是不太合适的。我们不需要追求最优算法,那样代价太高,能达到次优就行了。设计一套通用内存管理算法,通过一些参数对它进行配置,可以让它在特定情况也有相当出色的表现,这就是可调性。

l         最大化局部性(Locality)

大家都知道,使用cache可以提高程度的速度,但很多人未必知道cache使程序速度提高的真正原因。拿CPU内部的cache和RAM的访问速度相比,速度可能相差一个数量级。两者的速度上的差异固然重要,但这并不是提高速度的充分条件,只是必要条件。

另外一个条件是程序访问内存的局部性(Locality)。大多数情况下,程序总访问一块内存附近的内存,把附近的内存先加入到cache中,下次访问cache中的数据,速度就会提高。否则,如果程序一会儿访问这里,一会儿访问另外一块相隔十万八千里的内存,这只会使数据在内存与cache之间来回搬运,不但于提高速度无益,反而会大大降低程序的速度。

因此,内存管理算法要考虑这一因素,减少cache miss和page fault。

l         最大化调试功能

作为一个C/C++程序员,内存错误可以说是我们的噩梦,上一次的内存错误一定还让你记忆犹新。内存管理器提供的调试功能,强大易用,特别对于嵌入式环境来说,内存错误检测工具缺乏,内存管理器提供的调试功能就更是不可或缺了。

l         最大化适应性

前面说了最大化可调性,以便让内存管理器适用于不同的情况。但是,对于不同情况都要去调设置,无疑太麻烦,是非用户友好的。要尽量让内存管理器适用于很广的情况,只有极少情况下才去调设置。

设计是一个多目标优化的过程,有些目标之间存在着竞争。如何平衡这些竞争力是设计的难点之一。在不同的情况下,这些目标的重要性又不一样,所以根本不存在一个最好的内存分配算法。

关于glibc的内存分配器,我们并打算做代码级分析,只谈谈几点有趣的东西:

1.         Glibc分配算法概述:

l         小于等于64字节:用pool算法分配。

l         64到512字节之间:在最佳凭配算法分配和pool算法分配中取一种合适的。

l         大于等于512字节:用最佳凭配算法分配。

l         大于等于128K:直接调用OS提供的函数(如mmap)分配。

2.         Glibc扩展内存的方式:

l         int brk(void *end_data_segment);

本函数用于扩展堆空间(堆空间的定义可参考内存模型一章),用end_data_segment指明堆的结束地址。

l         void *sbrk(ptrdiff_t increment);

本函数用于扩展堆空间(堆空间的定义可参考内存模型一章),用increment指定要增加的大小。

l         void*  mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);

本函数用于分配大块内存了,如前面所述大于128K的内存。

3.         空指针和零长度内存

l         free(NULL)会让程序crash吗?答案是不会,标准C要求free接受空指针,然后什么也不做。

l         malloc(0)会分配成功吗?答案是会的,它会返回一块最小内存给你。

4.         对齐与取整

l         内存管理器会保证分配出来的内存地址是对齐的,通常是4或8字节对齐。

l         内存管理器会对要求内存长度取整,让内存长度能被4或8的整除。

5.         已经分配内存的结构

如果前面有一块有效内存块的,则第一个size_t指明前一块内存的大小。

第二个size_t指明自己的大小,同时还指明:自己是不是用mmap分配的(M),前面是否有一个效内存块(P)。你可能觉得奇怪,在32位机上,sizeof(size_t)就是32位,怎么还能留下两个位来保存标志呢?前面我们说了,会对内存长度取整,保证最低2或3bits为0,即是空闲的。

6.         空闲内存的管理

由此可以看出,最小内存块的长度为16字节:

sizeof(size_t) +

sizeof(size_t) +

sizeof(void*) +

sizeof(void*) +

0

这一招非常管用,第一次看到时,感觉简直太巧妙了。这使得无需要额外的内存来管理空闲块,利用空闲块自己,把空闲块强制转换成一个双向链表就行了。

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow

大内高手 内存管理器相关推荐

  1. 大内高手—内存管理器

    大内高手-内存管理器 转载时请注明出处和作者联系方式:http://blog.csdn.net/absurd 作者联系方式:李先静 <xianjimli at hotmail dot com&g ...

  2. 内存管理器(二)边界标识法

    边界标识算法 前言 首先说明,我们这里的内存管理器主要是以模拟各种内存分配算法为主,从内存申请一片内存然后根据我们所选定的数据结构和算法,实现程序的堆空间的分配,至于内存分配详情我们会在Linux内核 ...

  3. 一个简单而强大的单片机内存管理器-不带内存碎片整理

    单片机简单内存管理器 本代码基于无操作系统的STM32单片机开发.功能强大.可申请到地址空间连续的不同大小的内存空间,且用户接口简单,使用方便 转载请注明出处:http://blog.csdn.net ...

  4. 内存管理器剖析:ptmalloc,windows,macOS

    目录 1. Ptmalloc 2. Windows内存管理器 3. Mac OS内存管理器 4.推荐阅读 核心分析器的优势在于它能够将堆内存解析为数百万个单独的内存块,这些内存块由堆内存管理器分配给应 ...

  5. C/C++内存管理器

    C标准库提供了malloc,free,calloc,realloc,C++标准库还提供了new, new[], delete, delete[].这些用来管理内存,看起来够用了,为啥还要自己写一个内存 ...

  6. flink的内存管理器MemoryManager

    Flink中通过MemoryManager来管理内存. 在MemoryManager中,根据要管理的内存的总量和和每个内存页的大小得到内存页的数量生成相应大小数量的内存页来作为可以使用的内存. pub ...

  7. C++性能优化(十一) —— 内存管理器性能分析

    一.PTMalloc2 1.PTMalloc2优点 (1)集成在glibc中,Linux主要发行版的通用实现. 2.PTMalloc2缺点 (1)后分配的内存先释放.由于ptmalloc2收缩内存是从 ...

  8. 桌面内存管理器(dwn.exe)占用内存过高时怎么办?

    桌面内存管理器(dwn.exe)占用内存过高,可以解决的办法多种多样. 桌面内存管理器(dwn.exe)占用内存过高主要是因为存在DWM内存泄漏, 也正是因为这样,DWN内存泄露,不会自动回收内存,导 ...

  9. 深入研究glibc内存管理器原理及优缺点

    最近查清了线上内存占用过大和swap使用频繁的原因:由于linux使用的glibc使用内存池技术导致的堆外内存暴增,基于这个过程中学习和了解了glibc的内存管理原理,和大家分享,如有错误请及时指出. ...

最新文章

  1. IHttpHandler 在SharePoint中的应用
  2. 服务器装系统无显示屏,服务器系统安装后没有桌面
  3. FBI警告公众小心USB充电器:可能是键盘记录仪KeySweeper
  4. python中零碎的一点东西
  5. 蒋涛,CSDN创始人,俺村的骄傲
  6. python反距离权重法_反距离权重法 (Spatial Analyst)—ArcMap | 文档
  7. elasticsearch 部署
  8. Python使用matplotlib可视化模拟班级学生分数柱状图和折线图
  9. Win10如何卸载自己安装的软件
  10. python如何处理inp文件_python 之文件操作
  11. off cpu linux,宋宝华: 用off-cpu火焰图进行Linux性能分析
  12. Linux虚拟网络基础 — Tap
  13. ubuntu系统,网页版音乐播放器无声音
  14. php5.4 eregi,帮助将PHP eregi转换为preg_match
  15. 获取指定年、月的具体天数
  16. 每日一面 - mysql中,我存十亿个手机号码,考虑存储空间和查询效率,怎么设计?
  17. 状态模式、有限状态机 Unity版本实现
  18. Unity中获取一个物体下所有的子物体的方法
  19. 游戏手柄计算机,电脑游戏手柄怎么设置 电脑游戏手柄设置步骤【图文】
  20. Android 平台最新资讯(《Google android 入门开发与实战》pdf完整下载)

热门文章

  1. 逆透视变换(IPM)多种方式及代码总结
  2. 计算机网络实训报告总结,学习计算机网络的实训总结
  3. Android-使用StaticLayout实现icon跟随TextView末尾效果
  4. 如何利用 Github 搭建自己的免费图床?
  5. 使用echarts画日历热力图
  6. 又一个IGame的bug
  7. python中随机生成数字方法
  8. 使用 Raspberry Pi 和 CUPS 设置打印服务器
  9. 腾讯T3手把手教你!从底层开始带你了解并发编程,重要概念一网打尽!
  10. 自定义流程比较全的表结构