【形象解析】ptmalloc、tcmalloc与jemalloc对比

前言

对于ptmalloc,tcmalloc,jemalloc网上有很多解析,讲的很好也很仔细,但是想要彻底看懂还是很有难度的,我这篇文章主要以自己的理解并结合形象的举例对比三者的区别,相对于大部分文章我不会深入的探讨三者的具体结构,而是从接触新手的角度,通过对比三者的区别,以举例子让大家对这三个常见内存池有一个整体且直观的概念,其中有很多地方舍弃了结构设计的细节,只保留核心的申请释放过程,讲解相对来讲没有那么严谨,如有错误请在评论区指正。

一、内存池

1)池化技术

池化技术是指将一类资源统一管理并重复利用,以减少资源分配和释放的频率,从而提升效率并降低系统开销。在内存管理中,池化技术主要用于小对象的内存分配,通过预先分配一块较大的内存区域,将其划分为多个固定大小的小块以满足频繁的内存请求。池化技术的核心思想是“重用”,尤其在那些内存分配和释放非常频繁的应用中,这种技术能够显著提高性能。

池化技术就像餐馆里的自助餐盘回收机制。想象一个高峰时段的餐馆,如果每次客人用餐后都需要餐馆去购买新的餐盘,显然效率会非常低,还会浪费资源。为了避免这种情况,餐馆会准备一批固定数量的餐盘,当客人用完后,服务员会清洗并重新放回取餐区域供下一个客人使用。这种重复利用餐盘的方式,不仅节省了资源,还让整个用餐流程更加高效。

在内存管理中,池化技术就像这些餐盘:系统预先准备了一批内存块,程序用完后会将它们归还,供后续的内存请求使用,从而避免频繁向操作系统申请和释放内存所带来的开销与混乱。

池化的优点包括:

  • 减少分配开销:减少调用操作系统的内存分配接口(如 mallocnew)的次数。
  • 提升性能:固定大小的内存块分配更快,同时避免碎片化问题。
  • 降低内存碎片:通过统一管理,池化技术更容易控制和优化内存布局。

典型应用场景包括网络编程中的连接池、线程池,以及游戏开发中的对象池等。

2)内存池

内存池是一种基于池化技术实现的内存管理机制,它通过预分配一块内存区域,并对其进行统一管理,为小对象的内存分配提供支持。内存池通常会按照特定规则将内存分为多个固定大小的块(或称为“单元”),并在需要时将这些块分配给用户,释放时再归还到内存池中以供后续使用。

内存池的核心在于复用已分配的内存块,而不是频繁向操作系统请求和释放内存。这样可以显著降低系统调用的开销,同时避免因频繁分配和释放而导致的内存碎片问题。

1. 内存池的基本原理与目标
  • 预分配内存

    • 内存池在初始化时一次性向操作系统申请一大块连续的内存区域。
    • 这块区域被划分为若干个大小一致的内存块,以支持频繁的小对象分配需求。
  • 内存管理策略

    • 空闲链表:内存池会维护一个空闲链表,用于记录所有未被分配的内存块。当有新的分配请求时,从链表中取出一个空闲块并返回;释放时再将其归还到链表中。

    • 分区分配:有些内存池实现会根据块大小将内存池划分为不同的区域,以适配不同大小的对象分配需求。

  • 减少系统调用

    • 通过复用内存块,内存池可以减少对操作系统的内存分配和释放调用(如 mallocfree),降低了系统调用带来的开销。
  • 目标

    • 提升效率:提供更快的内存分配和释放速度。

    • 减少碎片:通过固定大小块的分配,避免内存碎片问题。

    • 优化资源利用率:内存池可以帮助应用程序在高并发场景中高效管理内存,减少内存不足的问题。

2. 内存池设计考虑

为了实现一个高效的内存池,在设计中需要考虑以下关键因素:

  • 分配效率:如何快速找到一个可用的内存块?是否需要支持多线程并发分配?

  • 内存利用率:设计合理的块大小,以避免因分配过多大块内存而浪费资源。

  • 线程安全:是否需要对内存池进行线程同步,或者采用线程本地池来减少锁争用?

  • 可扩展性:如果内存池的预分配区域不够,是否支持动态扩展?如何回收不再使用的内存块?

  • 内存对齐:确保分配的内存满足平台对齐要求,避免因未对齐导致的性能问题或错误。

  • 内存生命周期管理:如何确保分配的内存块在释放时被正确归还?是否需要垃圾回收机制?

  • 定位错误:为了调试方便,内存池应提供检测非法访问或重复释放的机制。

  • 跨平台支持:内存池的实现应尽可能适配多种操作系统和硬件架构。

  • 内存监控:提供内存池的使用统计(如分配次数、空闲块数量)以方便调试和优化。

二、ptmalloc

1)介绍

20 世纪 90 年代,随着多核处理器和多线程编程模型的普及,传统的内存分配器(如 dlmalloc)因其单线程设计,在并发场景中表现不佳,特别是在多线程程序频繁调用 mallocfree 时,容易导致锁争用,进而成为性能瓶颈。

为了应对这一问题,ptmalloc(pthread malloc)应运而生。它在 dlmalloc 的基础上进行了优化,通过引入线程局部内存管理策略,减少了全局锁的竞争,从而提升了多线程环境下的内存分配效率。

具体来讲,ptmalloc 是由 Wolfgang Gloger 在 1997 年开发的基于 dlmalloc(Doug Lea Malloc)的改进版本,专为解决多线程环境中的内存分配问题。随着多线程和多核处理器的普及,传统的单线程内存分配器(如 dlmalloc)在并发场景下效率较低,尤其在频繁调用 mallocfree 时容易发生锁争用,影响性能。ptmalloc 基于 dlmalloc,通过引入多线程支持的 arena 机制,显著优化了并发环境中的内存分配效率。

可以把 ptmalloc 的改进形象地看成一个大型自助餐厅的服务流程优化:

在传统的餐厅(类似于 dlmalloc)中,每次客人(线程)需要用餐时,都必须到服务台排队领取食物(获取内存)(类似于调用 malloc)。如果餐厅很忙,所有客人都集中到一个服务台,就会造成拥堵(即锁争用),影响用餐效率。

而在改进后的餐厅(类似于 ptmalloc)中,餐厅经理(ptmalloc 的设计者)决定把食物分散到不同的区域,每个区域都有一套独立的自助食物领取站(arena)。每位客人按照就近的规则到自主食物领取站获取食物,不需要再排队到服务台,只有在一个领取站食物完全消耗,才会需要经理协调重新补充(对应极少的全局锁操作)。

这种改进的好处是:

  • 每个区域的服务都是独立的(即一个arena有一把锁,如果不向同一个arena索要内存就不会加锁),不会互相干扰。
  • 减少了集中管理带来的排队和等待(全局锁争用),提升了整体效率。
  • 适合高峰期使用(多线程高并发场景)。

通过这种优化,ptmalloc 在多线程环境下的内存分配性能得到了显著提升,就像改进后的餐厅能更高效地服务客人一样。

2)ptmalloc解析

1. 核心概念

了解ptmalloc前我们要明白两个核心概念:

  • Arena(分配区):每个线程会优先使用自己的分配区,减少与其他线程的锁竞争。如果没有可用的分配区,系统会动态创建新的分配区。

  • Chunk(内存块):指内存池中分配的最小单位,每次内存申请都会从Arena分配区中切割出适合大小的内存块返回给用户。对于超大内存申请,直接调用操作系统的 mmap 接口分配内存。

2. 线程与分配器的关系

ptmalloc 通过 动态创建多个 arena 来应对多线程的内存分

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值