当前位置: 首页 > news >正文

malloc:arena

多线程应用中,并发调用malloc,malloc的实现中,多线程之间需要锁进行同步吗?

大部分时候是不需要的。每个线程有自己的tcache,有自己的arena,有自己的堆。

所以说,对于多线程的进程来说,多个线程有自己的堆,而不是共用一个堆。

glibc中的malloc管理,为了减小多线程之间并发调用malloc时的同步,引入了arena和tcache。

1arena

NARENAS_FROM_NCORES(n) ((n) * (sizeof (long) == 4 ? 2 : 8))

arena的个数是有限制的,最大值由宏NARENAS_FROM_NCORES定义,n是cpu个数。可以看到在32位系统上,arena的最大值是cpu个数乘以2,在64位系统上,arena最大值是cpu的个数乘以8。当arena个数小于最大值时,那么每个线程使用自己的arena,当arena个数大于最大值时,那么便会有arena被多个线程共用。

static mstate
_int_new_arena (size_t size)
{mstate a;heap_info *h;char *ptr;unsigned long misalign;h = new_heap (size + (sizeof (*h) + sizeof (*a) + MALLOC_ALIGNMENT),mp_.top_pad);...a = h->ar_ptr = (mstate) (h + 1);malloc_init_state (a);...top (a) = (mchunkptr) ptr;set_head (top (a), (((char *) h + h->size) - ptr) | PREV_INUSE);...__libc_lock_lock (a->mutex);return a;
}

当线程第一次调用malloc,会创建一个arena,通过函数_int_new_arena 实现。

通过new_heap申请一个堆内存,申请的堆内存初始化之后的情况如上图所示:

(1)开头存放struct heap_info结构体

(2)struct heap_info之后存放struct malloc_state,也就是arena

(3)struct heap_info之后是top chunk,堆内存初始化的时候,所有的内存都放到top chunk中。

第一次申请内存的时候,fast bin, small bin, unsorted bin, large bin都是空的,这个时候,就从top trunk中截取一段内存返回给用户,同时移动top trunk的位置。可以看到,随着内存不断的申请,top trunk会被切分成很多小块的内存。内存释放时,也就是用户调用free的时候,内存会根据大小放到不同的bin中。

2tcache

因为arena有最大个数限制,当线程个数大于最大值的时候,就会存在一个arena被多个线程共享的情况,为了减小这种竞争,引入了tcache。

申请内存的判断顺序:tcache --> fast bin --> small bin --> unsorted bin --> top chunk --> 系统调用

3main_arena

主线程申请内存时,从main_arena中申请。main_arena是静态定义的,不需要像子线程那样通过new_heap申请一个新的堆,然后在堆上初始化一个arena。初始的main_arena是内存的,top chunk也没有,所以第一次从哪个main_arena中申请内存时,需要从系统申请内存。

static struct malloc_state main_arena =
{.mutex = _LIBC_LOCK_INITIALIZER,.next = &main_arena,.attached_threads = 1
};

主线程的堆内存,通过sbrk来申请。

(gdb) bt
#0  __GI___sbrk (increment=135168) at ./misc/sbrk.c:37
#1  0x00007ffff78a25c6 in __glibc_morecore (increment=<optimized out>) at ./malloc/morecore.c:29
#2  0x00007ffff78a35f9 in sysmalloc (nb=nb@entry=656, av=av@entry=0x7ffff7a1ac80 <main_arena>) at ./malloc/malloc.c:2727
#3  0x00007ffff78a48dd in _int_malloc (av=av@entry=0x7ffff7a1ac80 <main_arena>, bytes=bytes@entry=640) at ./malloc/malloc.c:4407
#4  0x00007ffff78a49c9 in tcache_init () at ./malloc/malloc.c:3245
#5  0x00007ffff78a51de in tcache_init () at ./malloc/malloc.c:3241
#6  __GI___libc_malloc (bytes=72704) at ./malloc/malloc.c:3306
#7  0x00007ffff7caa93a in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6
#8  0x00007ffff7fc947e in call_init (l=<optimized out>, argc=argc@entry=1, argv=argv@entry=0x7fffffffe468, env=env@entry=0x7fffffffe478)
at ./elf/dl-init.c:70
#9  0x00007ffff7fc9568 in call_init (env=0x7fffffffe478, argv=0x7fffffffe468, argc=1, l=<optimized out>) at ./elf/dl-init.c:33
#10 _dl_init (main_map=0x7ffff7ffe2e0, argc=1, argv=0x7fffffffe468, env=0x7fffffffe478) at ./elf/dl-init.c:117
#11 0x00007ffff7fe32ca in _dl_start_user () from /lib64/ld-linux-x86-64.so.2
#12 0x0000000000000001 in ?? ()
#13 0x00007fffffffe6d1 in ?? ()
#14 0x0000000000000000 in ?? ()
(gdb)

通过proc中maps文件,可以看到,标记heap的是主线程的堆,标记stack的是主线程的栈。子线程的堆和栈,均是通不过mmap申请的。

557bac31f000-557bac340000 rw-p 00000000 00:00 0                          [heap]
7fff2c7e7000-7fff2c808000 rw-p 00000000 00:00 0                          [stack]

http://www.dtcms.com/a/434781.html

相关文章:

  • 第12课:构建对话记忆:打造多轮对话RAG机器人
  • 大良营销网站建设如何模板网站没有源代码
  • 归并排序的递归和非递归实现
  • 天津建设网站个人主页网页设计模板免费
  • 整体设计 逻辑系统程序 之8 三种逻辑表述形式、形式化体系构建及关联规则(正则 / 三区逻辑)
  • 京东Java后台开发面试题及参考答案(上)
  • 婚纱摄影网站帮忙建设公司网站
  • 载具系统介绍
  • 理解采样操作的不可微性及重参数化技巧
  • 做网站 视频外链做网站的做网站麻烦吗
  • TOGAF之架构标准规范-需求管理
  • 临沂 企业网站建设seo双标题软件
  • 公司为什么做网站支付宝小程序
  • Linux中读写自旋锁rwlock的实现
  • 前端-JS基础-day5
  • 字体版权登记网站WordPress网站结构优化
  • [特殊字符]【保姆级教程】GLM-4.6 接入 Claude Code:200K 长上下文 + Agentic Coding,开发者福音!编程能力大幅提升!
  • 大前端开发技术知识框架详解、Mono repo工程化实践详解、微前端实践详解
  • MDK编译过程
  • 网站整体风格设计ios aso优化工具
  • 数据结构KMP算法详解:C语言实现
  • 【网络通讯安全认证的理解:从密钥签名、数字证书到 HTTPS/TLS 流程】
  • 蜘蛛抓取网站模块原理推广是怎么做的
  • 中国石油AI中台-昆仑大模型介绍(二)
  • RAG核心特性:查询增强和关联
  • Spring 中事务的实现
  • 苏州哪家公司做网站网站布局是什么
  • AI智能体在研究分析中的仿真应用:预测、生存与建构——情绪是基于趋利避害的预测机制吗?
  • 12.排序(上)
  • Java bean 数据校验