没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论









1
目录
1. 问题........................................................................................................................................... 3
2. 基础知识 ................................................................................................................................... 4
2.1 X86 平台 Linux 进程内存布局 ..................................................................................... 4
2.1.1 32 位模式下进程内存经典布局 ...................................................................... 4
2.1.2 32 位模式下进程默认内存布局 ...................................................................... 5
2.1.3 64 位模式下进程内存布局 .............................................................................. 5
2.2 操作系统内存分配的相关函数 ................................................................................... 6
2.2.1 Heap 操作相关函数 ......................................................................................... 6
2.2.2 Mmap 映射区域操作相关函数 ....................................................................... 7
3. 概述........................................................................................................................................... 8
3.1 内存管理一般性描述 ................................................................................................... 8
3.1.1 内存管理的方法 ............................................................................................... 8
3.1.2 内存管理器的设计目标 ................................................................................. 10
3.1.3 常见 C 内存管理程序 ..................................................................................... 12
3.2 Ptmalloc 内存管理概述 .............................................................................................. 13
3.2.1 简介 ................................................................................................................. 13
3.2.2 内存管理的设计假设 ..................................................................................... 14
3.2.3 内存管理数据结构概述 ................................................................................. 14
3.2.4 内存分配概述 ................................................................................................. 19
3.2.5 内存回收概述 ................................................................................................. 21
3.2.6 配置选项概述 ................................................................................................. 22
3.2.7 使用注意事项 ................................................................................................. 23
4. 问题分析及解决 ..................................................................................................................... 24
5. 源代码分析 ............................................................................................................................. 26
5.1 边界标记法 ................................................................................................................. 26
5.2 分箱式内存管理 ......................................................................................................... 34
5.2.1 Small bins ........................................................................................................ 34
5.2.2 Large bins ........................................................................................................ 35
5.2.3 Unsorted bin .................................................................................................... 40
5.2.4 Fast bins ........................................................................................................... 42
5.3 核心结构体分析 ......................................................................................................... 44
5.3.1 malloc_state .................................................................................................... 44
5.3.2 Malloc_par ...................................................................................................... 47
5.3.3 分配区的初始化 ............................................................................................. 49
5.4 配置选项 ..................................................................................................................... 51
5.5 Ptmalloc 的初始化...................................................................................................... 53
5.5.1 Ptmalloc 未初始化时分配/释放内存 ............................................................ 53
5.5.2 ptmalloc_init()函数 ......................................................................................... 55
5.5.3 ptmalloc_lock_all(),ptmalloc_unlock_all(),ptmalloc_unlock_all2() ................ 60
5.6 多分配区支持 ............................................................................................................. 65
5.6.1 Heap_info ........................................................................................................ 65
5.6.2 获取分配区 ..................................................................................................... 66

2
5.6.3 Arena_get2() ................................................................................................... 68
5.6.4 _int_new_arena() ............................................................................................ 70
5.6.5 New_heap() ..................................................................................................... 72
5.6.6 get_free_list()和 reused_arena() .................................................................... 75
5.6.7 grow_heap(),shrink_heap(),delete_heap(),heap_trim() ................................. 77
5.7 内存分配 malloc ......................................................................................................... 82
5.7.1 public_mALLOc() ............................................................................................. 82
5.7.2 _int_malloc() ................................................................................................... 83
5.8 内存释放 free ........................................................................................................... 116
5.8.1 Public_fREe() ................................................................................................. 116
5.8.2 _int_free() ..................................................................................................... 118
5.8.3 sYSTRIm()和 munmap_chunk() ..................................................................... 126

3
1. 问题
项目组正在研发的一个类似数据库的 NoSql 系统,遇到了 Glibc 的内存暴增问题。现象
如下:在我们的 NoSql 系统中实现了一个简单的内存管理模块,在高压力高并发环境下长时
间运行,当内存管理模块的内存释放给 C 运行时库以后,C 运行时库并没有立即把内存归还
给操作系统,比如内存管理模块占用的内存为 10GB,释放内存以后,通过 TOP 命令或者
/proc/pid/status 查看进程占用的内存有时仍然为 10G,有时为 5G,有时为 3G,etc,内存释
放的行为不确定。
我们的 NoSql 系统中的内存管理方式比较简单,使用全局的定长内存池,内存管理模块
每次分配/释放 2MB 内存,然后分成 64KB 为单位的一个个小内存块用 hash 加链表的方式进
行管理。如果申请的内存小于等于 64KB 时,直接从内存池的空闲链表中获取一个内存块,
内存释放时归还空闲链表;如果申请的内存大于 64KB,直接通过 C 运行时库的 malloc 和 free
获取。某些数据结构涉及到很多小对象的管理,比如 Hash 表,B-Tree,这些数据结构从全
局内存池获取内存后再根据数据结构的特点进行组织。为了提高内存申请/释放的效率,减
少锁冲突,为每一个线程单独保留 8MB 的内存块,每个线程优先从线程专属的 8MB 内存块
获取内存,专属内存不足时才从全局的内存池获取。
系统中使用的网络库有独立的内存管理方式,并不从全局内存池中分配内存,该网络库
在处理网络请求时也是按 2M 内存为单位向 C 运行时库申请内存,一次请求完成以后,释放
分配的内存到 C 运行时库。
在弄清楚了系统的内存分配位置以后,对整个系统进行了内存泄露的排查,在解决了数
个内存泄露的潜在问题以后,发现系统在高压力高并发环境下长时间运行仍然会发生内存暴
增的现象,最终进程因 OOM 被操作系统杀掉。
为了便于跟踪分析问题,在全局的内存池中加入对每个子模块的内存统计功能:每个子
模块申请内存时都将子模块编号传给全局的内存池,全局的内存池进行统计。复现问题后发
现全局的内存池的统计结果符合预期,同样对网络模块也做了类似的内存使用统计,仍然符
合预期。由于内存管理不外乎三个层面,用户管理层,C 运行时库层,操作系统层,在操作
系统层发现进程的内存暴增,同时又确认了用户管理层没有内存泄露,因此怀疑是 C 运行时
库的问题,也就是 Glibc 的内存管理方式导致了进程的内存暴增。
问题范围缩小了,但有如下的问题还没有搞清楚,搞不清楚这些问题,我们系统的中的
问题就无法根本性解决。
1. Glibc 在什么情况下不会将内存归还给操作系统?
2. Glibc 的内存管理方式有哪些约束?适合什么样的内存分配场景?
3. 我们的系统中的内存管理方式是与 Glibc 的内存管理的约束相悖的?
4. Glibc 是如何管理内存的?
带着这些问题,决定对 Glibc 的 ptmalloc2 源代码进行一番研究,希望能找到这些问题的
答案,并解决我们系统中遇到的问题。我研究的对象是当前最新版的 glibc-2.12.1 中的内存
管理的相关代码。

4
2. 基础知识
2.1 X86 平台 Linux 进程内存布局
Linux 系统在装载 elf 格式的程序文件时,会调用 loader 把可执行文件中的各个段依次
载入到从某一地址开始的空间中(载入地址取决 link editor(ld)和机器地址位数,在 32 位机
器上是 0x8048000,即 128M 处)。如下图所示,以 32 位机器为例,首先被载入的是.text 段,
然后是.data 段,最后是.bss 段。这可以看作是程序的开始空间。程序所能访问的最后的地
址是 0xbfffffff,也就是到 3G 地址处,3G 以上的 1G 空间是内核使用的,应用程序不可以直
接访问。应用程序的堆栈从最高地址处开始向下生长,.bss 段与堆栈之间的空间是空闲的,
空闲空间被分成两部分,一部分为 heap,一部分为 mmap 映射区域,mmap 映射区域一般
从 TASK_SIZE/3 的地方开始,但在不同的 Linux 内核和机器上,mmap 区域的开始位置一般是
不同的。Heap 和 mmap 区域都可以供用户自由使用,但是它在刚开始的时候并没有映射到
内存空间内,是不可访问的。在向内核请求分配该空间之前,对这个空间的访问会导致
segmentation fault。用户程序可以直接使用系统调用来管理 heap 和 mmap 映射区域,但更
多的时候程序都是使用 C 语言提供的 malloc()和 free()函数来动态的分配和释放内存。Stack
区域是唯一不需要映射,用户却可以访问的内存区域,这也是利用堆栈溢出进行攻击的基础。
2.1.1 32 位模式下进程内存经典布局
这种布局是 Linux 内核 2.6.7 以前的默认进程内存布局形式,mmap 区域与栈区域相对增
长,这意味着堆只有 1GB 的虚拟地址空间可以使用,继续增长就会进入 mmap 映射区域,
这显然不是我们想要的。这是由于 32 模式地址空间限制造成的,所以内核引入了另一种虚
拟地址空间的布局形式,将在后面介绍。但对于 64 位系统,提供了巨大的虚拟地址空间,
这种布局就相当好。

5
2.1.2 32 位模式下进程默认内存布局
从上图可以看到,栈至顶向下扩展,并且栈是有界的。堆至底向上扩展,mmap 映射区
域至顶向下扩展,mmap 映射区域和堆相对扩展,直至耗尽虚拟地址空间中的剩余区域,这
种结构便于 C 运行时库使用 mmap 映射区域和堆进行内存分配。上图的布局形式是在内核
2.6.7 以后才引入的,这是 32 位模式下进程的默认内存布局形式。
2.1.3 64 位模式下进程内存布局
在 64 位模式下各个区域的起始位置是什么呢?对于 AMD64 系统,内存布局采用经典
内存布局,text 的起始地址为 0x0000000000400000,堆紧接着 BSS 段向上增长,mmap 映射
区域开始位置一般设为 TASK_SIZE/3。
#define TASK_SIZE_MAX ((1UL << 47) - PAGE_SIZE)
#define TASK_SIZE (test_thread_flag(TIF_IA32) ? \
IA32_PAGE_OFFSET : TASK_SIZE_MAX)
#define STACK_TOP TASK_SIZE
#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3))
计 算 一 下 可 知 , mmap 的 开 始 区 域 地 址 为 0x00002AAAAAAAA000 , 栈 顶 地 址 为
0x00007FFFFFFFF000
剩余128页未读,继续阅读
资源评论

悠闲饭团
- 粉丝: 91
- 资源: 2028

上传资源 快速赚钱
我的内容管理 收起
我的资源 快来上传第一个资源
我的收益
登录查看自己的收益我的积分 登录查看自己的积分
我的C币 登录后查看C币余额
我的收藏
我的下载
下载帮助

会员权益专享
最新资源
- 第4次作业_计算税后工资.cpp
- 校园管理 - 学生管理系统源码
- 1047538782469312MOJiRead_channel_google_code_1.5.5_60_20230314182834_NO-HW_release.apk
- stm32的nucleo开发板点亮LED的汇编程序
- WPSOffice-v17.3.2(1394)-v8a,v7a-Balatan.apk
- python练习题代码参考-职工管理系统
- python读取某文件夹下的所有文件名将读出的文件名输出到CSV文件
- Sparse_Identification_Part2.mlx
- python斐波那契数列
- python非递归方式计算阶乘(循环)
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈



安全验证
文档复制为VIP权益,开通VIP直接复制
