堆基础
brk
系统调用
将进程的堆结束地址(prgram break)设置为指定的值,从而控制堆内存的大小。
可以扩展或收缩堆内存
1 |
|
addr:
指定新的堆结束地址
成功时,返回0
失败时,返回-1,设置errno
为以下之一:
ENOMEN
内存不足,无法扩展到指定的地址EINVAL
指定的地址无效
sbrk
Unix/Linux系统中的一个系统调用
通过增加或减少进程的堆结束地址(Program break)来分配或释放内存。
1 |
|
increment
:堆内存的调整量,以字节为单位。可为正数、负数或零
- 正值:增加堆的大小,向系统申请更多内存空间
- 负值:减少堆的大小,释放之前分配的内存
- 零:不改变堆的大小,此时函数返回当前堆的结束地址
返回值: - 成功时,
- 如果
increment
是负数,返回调整前的堆顶地址。 - 如果
increment
是正值,则返回值指向新分配内存的堆顶地址 - 如果
increment
是0,返回当前堆的结束地址(program break)
- 如果
- 失败时,返回
(void *)-1
,并设置errno
为ENOMEM
,表示没有足够的内存
getpid
系统调用
返回当前进程的PID
常用调试命令heap
vmmap
vis_heap_chunks
top_chunk
bin
arenas
arena
1 |
|
tcache
glibc从2.26版本开始引入的一种内存管理机制,旨在提高内存分配的性能。
tcache(thread cache)是一种线程本地缓存机制,每个线程都有自己的tcache结构,它类似于fastbin,但是优先级上高于fastbin
减少线程之间的互斥 和 锁的竞争
当程序进行malloc
操作时,会优先检查tcache是否有可用的chunk,如果有,就直接返回;
当进行free
操作时,如果chunk的大小符合要求,并且对应的tcache bin还未满(默认每个bin可以存放7个chunk),就会把chunk放入tcache。
了解堆
Top chunk:程序第一次进行malloc的时候,heap会被分为两块,一块给用户,剩下的那块就是top chunk,再次申请堆块要是没合适的空间便会使用top chunk的空间
你申请到的一块堆内存的起始地址 $\neq$ 你可以写入数据的起始地址,因为堆块头部会记录一些信息,在64位条件下会有0x10大小的差距
你申请的大小 $\neq$ 实际申请的大小,他会有一个取整的步骤
一般使用free()函数释放的堆块不会立刻被回收,它们会变成一种叫free chunk的东西并且加上了一种类似xxx bin的名字,一般这类堆块释放后如果挨着一个也被释放的堆块或者是top chunk会合并
fast bin是一个特例 – 它不会轻易合并
1 |
|
Arena
在glibc的内存管理机制中,arena(分配区)是ptmalloc(glibc所用的内存分配器)用于管理进程内存的核心结构之一
它通过减少线程间的锁竞争来提升多线程环境下内存分配的性能
类型
- 主分配区(main arena):只能由第一个线程创建和持有,可以使用
sbrk
和mmap
向操作系统申请内存 - 非主分配区(Non-main Arena):由其它线程创建,只能通过mmap向操作系统申请内存
查看系统libc版本号
1 |
|
64位
以 0x10 <= userdata < 0x20为例
userdata: <= 0x18 共分配0x20
userdata: > 0x18 共分配0x30
这样分配和chunk间复用和size、PRE_INUSE字段有关
各ubunut版本常用的libc版本
Ubuntu18.04 2.27
2.35的堆io