glibc内存管理

X86平台LINUX进程内存布局如下:

上面个段的含义如下:

  • text:存放程序代码的,编译时确定,只读;
  • data:存放程序运行时就能确定的数据,可读可写;
  • bss:定义而没有初始化的全局变量和静态变量;
  • heap:一般由程序员分配,如果不释放的话在程序结束的时候可能被OS回收;
  • stack:有编译器自动分配释放,存放函数的参数、局部变量等;
  • Mmap:映射区域;

程序可以直接使用系统调用来管理heap和mmap,但更多的时候是使用C提供的malloc和free来动态地分配和释放内存。Linux上的stack的限制大致是8M,而在Windows上为2M。


C风格的内存管理程序:

  • 也就是malloc和free,主要是通过brk或者mmap添加额外的虚拟内存。对于那些需要保持长期存储的程序使用malloc来管理内存可能会非常令人失望,如果有大量的不固定的内存引用,经常难以知道他们如何被释放。

池式内存管理:

  • 应用程序可以更简单地管理内存;内存分配和回收更快;可以预先分配错误处理池,以便程序在常规内存被耗尽时仍然可以恢复;有非常易于使用的标准实现。
  • 内存池只适用于操作可以分阶段的程序;通常不能和第三方库很好滴合作;如果程序的结构发生变化则不得不修改内存池;必须记住需要从哪个池进行分配。

引用计数:

  • 不能忘记调用引用计数函数;无法释放作为循环数据结构的一部分;在多线程环境中更难也更慢。

垃圾回收:

  • 永远不必担心内存的双重释放或者对象的生命周期;
  • 无法干涉何时释放内存;比其他形式的内才能管理更慢;如果忘记将不再使用的指针设置为null,仍然会有内存泄露(《Effective Java》中有讲)。

内存管理器的设计目标:

  1. 最大化兼容性;
  2. 最大化可移植性(能很好地和OS交流);
  3. 浪费最小的空间(管理自身的数据结构也是需要内存的,还有一个需要注意的是碎片); 
  4. 最快的速度(2/8原则,主要用来优化热点);
  5. 最大化可调性(能适应多种分配的需求,或者是通过配置来适应);
  6. 最大化局部性(这里考虑的是CPU的cache和内存之间的关系);
  7. 最大化调试功能(作为程序员就不用说了);
  8. 最大化适应性(在不修改配置时候的适应性);

ptmalloc实现了malloc和free以及一组其他函数,以提供动态内存管理的支持。分配器处于用户程序和内核之间,用来响应用户的分配请求,向操作系统申请内存,然后将其返回给用户程序。为了保持高效的分配,分配器一般都会预先分配一大块内存,并通过某种算法管理。用户释放掉的内存也并不是立即就返回给操作系统。ptmalloc在设计的时候折中了高效性、高空间利用率、高可用性等设计目标。其设计假设如下:

  1. 用mmap来分配长生命周期的大内存;
  2. 特别大的内存分配总是使用mmap;
  3. 短生命周期的内存分配使用brk;
  4. 尽量只缓存小的、临时使用的内存,而大的内存则直接归还给系统;
  5. 小内存块只有在malloc和free的时候进行合并;
  6. 收缩堆的条件是当前free的快的大小加上前后能合并的chunk的大小大于64K,并且堆顶的大小达到阀值;
  7. 需要长期存储的程序不适合ptmalloc;

总体上的结构如下:

而实际存在数据的是Chunk,使用中的Chunk的结构如下:

其中:

  • P:表示前一个Chunk是否在使用中;
  • M:标志Chunk是从那个内存区域获得的虚拟内存;
  • A:标志是否是主分配区;

空闲的Chunk在内存中的结构如下:

在glibc中使用bin来管理空闲的chunk,细节就不说了。当空闲的chunk被链接到bin中的时候,ptmalloc会检查他前后的chunk是否也是空闲的,如果是的话,就会合并成一个大的chunk。bin的结构如下:

ptmalloc为了提高分配的速度,会把一些小的chunk先放到Fast bins中。fast bins中的chunk并不改变它的使用标志P,这样也就无法将他们合并,当用户分配小的内存的时候,ptmalloc首先会在fast bins中查找响应的空闲块,然后再去查找Unsorted bins中空闲的chunk。被合并后的chunk、或者是不能放在fast bins中的chunk会首先放在Unsorted bin中,如果在分配的时候在Unsorted bin中无法满足要求,则将Unsorted bin中的chunk加入到bins中。

因为在分配内存的时候是用低地址到高地址分配的,这样一个分配到的大的内存(用来模拟sub-heap)的上面很有可能是有一块空闲的内存,也就是Top chunk。Top chunk是在fast bin和bins之后才考虑的,所以这段区间并不在bins这些结构中。如果ptmalloc设法在top chunk中分配一段空间时且top chunk不够大,这时会重新分配一个新的sub-heap,并将top chunk迁移到新的sub-heap上。新的sub-heap与已有的sub-heap用单向链表连接起来。如下:

当要分配的空间足够大的时候,ptmalloc会使用mmap来直接使用内存映射来讲页映射到进程空间。这样分配的chunk在被free时将直接接触映射,再次对这样的内存区域的引用将会引起段错误。

Last remainder chunk是另外一种特殊的chunk,在分配一个small chunk的时候,如果在small bins中找不到合适的chunk,如果last remainder chunk的大小大于所需的small chunk大小。那么它将会分裂成两个,一个供用户使用,另一个变成了新的Last remainder chunk。


ptmalloc的响应用户内存分配请求的具体步骤:

  1. 获取主分配区的锁,如果失败就查找非主分配区,再不行就创建新的非主分配区;
  2. 将用户请求的大小转换为实际需要分配的chunk空间的大小;
  3. 如果chunk_size<=max_fast则转4,否则,跳转5;
  4. 尝试在fast bins中分配,如果成功则结束返回;
  5. 如果chunk_size<=512B则下一步,否则跳转6;
  6. 查找对应的small bins,如果找到则分配成功;否则转7;
  7. 合并fast bins中的chunk,遍历unsorted bin中的chunk,如果只有一个chunk,并且这个chunk在上次的分配中被使用过,并且所需分配的chunk大小属于smallbins,并且chunk的大小满足要求,则直接将该chunk进行切割,分配结束;否则将其放入bins;
  8. 在large bins中查找;如果失败转9;
  9. 如果top chunk满足要求,则从中分配出一块;否则转10;
  10. 如果是主分配区,调用sbrk增加top chunk的大小;否则分配一个新的sub-heap;或者直接使用mmap来分配;如果需要用mmap分配转11,否则转12;
  11. 使用mmap系统调用为程序的内存空间映射一块空间,然后将指针返回给用户程序;
  12. 判断是否第一次调用malloc,若是主分配区,则进行一次初始化工作。否则根据10的规则来分配。 

为了避免Glibc内存暴增,使用时需要注意一下几点:

  1. 后分配的内存先释放(top chunk的考虑);
  2. 不适合用于管理长生命周期的内存,特别是持续不定期分配和释放长生命周期的内存;
  3. 不要关闭ptmalloc的mmap分配阀值动态调整机制;
  4. 多线程分阶段执行的程序不适合使用ptmalloc(更适合使用内存池);
  5. 尽量减少程序的线程数量和避免频繁分配、释放内存;
  6. ptmalloc对内存泄露非常敏感;
  7. 防止程序分配过多的内存而使得程序被因为OOM被系统杀掉。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: glibc是GNU计划的一部分,是一套C语言标准库。内存管理是其中的一个重要组件。而ptmalloc2是glibc内存管理的一种算法,用于分配和释放内存块。 要下载glibc内存管理ptmalloc2源代码,可以通过以下几个步骤进行: 1. 打开GNU官方网站,找到glibc的相关页面,通常在https://www.gnu.org/software/libc/ 。 2. 在该页面上,找到下载链接或源代码仓库地址,这个地址通常会提供给用户下载最新版本的glibc。 3. 点击下载链接或者复制源代码仓库地址,将其粘贴到浏览器地址栏中。 4. 打开该链接后,您将能够下载一个压缩文件(通常是tar.gz或tar.bz2格式),包含了glibc的全部源代码。 5. 下载完毕后,解压压缩文件。您可以使用解压软件,如WinRAR或7-Zip。解压缩后,您将获得一个包含许多目录和文件的文件夹。 6. 在解压后的文件夹中,找到与ptmalloc2相关的源代码文件。通常这些文件会位于glibc源代码的malloc目录下。 7. 在malloc目录中,您将能够找到ptmalloc2源代码文件,这些文件名通常以"ptmalloc"或"ptmalloc2"开头。 以上是下载glibc内存管理ptmalloc2源代码的一个大致过程。通过该源代码,您可以深入了解ptmalloc2算法是如何在glibc中实现内存分配和释放的。但是请注意,阅读和理解源代码需要一定的计算机编程经验和相关背景知识。 ### 回答2: glibc是Linux操作系统中非常重要的一个C标准库,ptmalloc2是glibc中负责内存管理的模块之一。该模块负责动态分配和释放内存,并提供了多种内存分配器算法。 ptmalloc2源代码分析是深入研究该模块源代码的过程。通过分析ptmalloc2源代码,可以了解到它的实现原理、内存分配算法以及性能优化等方面的细节。 在下载ptmalloc2源代码之后,我们可以通过阅读和分析源代码来了解其内部结构和工作原理。在源代码中,我们可以找到一些关键的数据结构和函数,如malloc、free、realloc等。这些函数实现了动态内存分配和释放的基本功能。 通过阅读源代码,我们可以学习到ptmalloc2内存管理器的特点和优势。例如,ptmalloc2采用了分离的空闲链表来管理不同大小的内存块,利用了空闲块合并和分割等技术来提高内存的利用率和性能。此外,源代码还可能包含一些与内存操作相关的底层函数和宏定义。 分析ptmalloc2源代码不仅可以帮助我们理解其内部实现,还可以为我们定位和解决内存管理相关的问题提供指导。如果遇到性能问题或者内存泄漏等现象,我们可以通过分析源代码来找到问题的根源,并提出相应的优化措施。 总之,通过对glibc内存管理模块ptmalloc2的源代码进行分析,我们可以深入了解其实现原理和内部机制,为我们在实际项目中正确、高效地使用内存管理功能提供帮助。 ### 回答3: glibc是Linux系统上使用最广泛的C语言函数库,而ptmalloc2则是glibc中负责内存分配和管理的部分源代码。 首先,需要明确的是,glibc的ptmalloc2源代码并不是一个独立的项目,而是glibc库中的一部分。如果需要下载该源代码,可以通过访问glibc的官方网站或者使用git等工具来获取。 分析glibc内存管理ptmalloc2源代码可以帮助开发者更好地理解和使用glibc的内存分配功能。ptmalloc2实现了一种基于堆的内存分配算法,它采用了多种策略来管理内存,如bin和fastbin等。源代码的分析可以帮助我们了解这些策略的具体实现细节,以及它们在不同场景下的行为。 要对ptmalloc2源代码进行分析,可以首先阅读相关文档,如glibc的官方文档或论文。 掌握ptmalloc2的整体架构、数据结构和算法等基本知识后,可以通过逐行或逐函数地阅读源代码来深入理解其内部工作机制。可以关注一些关键函数的实现,如malloc、free、realloc等,以及相关的数据结构和算法。 此外,还可以参考开源社区中对ptmalloc2源代码的分析和解读,如一些博客文章、论文或代码注释等。这些资源通常提供了对源代码更深入的解释和讨论,对于理解ptmalloc2的实现细节会有所帮助。 总之,通过下载并分析glibc内存管理ptmalloc2源代码,可以帮助我们更好地理解和使用glibc库中的内存分配功能。同时,也可以通过分析源代码来提高我们的代码调试和性能优化能力,并为开发更高效的内存管理算法提供参考。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值