ptmalloc - 第一次申请与释放大内存
glibc中malloc的代码包括了线程同步,平台兼容性等问题,但是本系列文章主要的研究对象ptmalloc。所以提供的代码都是经过简化,部分宏也会展开,能够说清楚ptmalloc的运行流程就可以了。
要点
- 用例
- 第一次申请大块内存
- 第一次释放大块内存
- 两章总结
用例
int main(void)
{
char *mem = malloc(0x20000);
free(mem);
return -1;
}
第一次申请大块内存
为什么malloc的字节数是0x20000,而不是4096或者其他呢?4096不够大么,不够,sysmalloc代码里面有这么一段
/* 对于我的测试环境来说 */
#define DEFAULT_MMAP_THRESHOLD 0x20000
static struct malloc_par mp_ =
{
...
.mmap_threshold = DEFAULT_MMAP_THRESHOLD,
...
};
if ((unsigned long) (nb) >= (unsigned long) (mp_.mmap_threshold)) {
... /* 更多关于大块内存分配的代码 */
}
在第一次分配内存的时候,DEFAULT_MMAP_THRESHOLD就是走入分岔口的判定条件,一条分岔口已经在分配小内存那一章说过了,这次说的就是另一条道路了,这条道路看起来轻松很多了,起码要看的代码可是少很多了。直接贴上sysmalloc的代码吧
static void *
sysmalloc (INTERNAL_SIZE_T nb, mstate av)
{
size_t pagesize = 0x1000;
long size;
char *mm;
mchunkptr p;
size = (nb + 8 + pagesize - 1) & -pagesize;
if (size > nb) {
mm = (char *)mmap(NULL, size,
PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (mm != (void *)-1) {
p = (mchunkptr)mm;
p->mchunk_prev_size = 0;
p->mchunk_size |= IS_MAPPED;
mp_.n_mmaps += 1;
mp_.max_n_mmaps = MAX(mp_.max_n_mmaps, mp_.n_mmaps);
mp_.mmaped_mem += size;
mp_.max_mmaped_mem = MAX(mp_.max_mmaped_mem, mp_.mmaped_mem);
return p + MIN_CHUNK_SIZE;
}
}
return NULL;
}
第一次释放大块内存
从上面的代码可以看到,申请大块内存是使用mmap,那么释放肯定就是用munmap了
释放的代码量更少了,就是释放,设置。Talk is cheap, show me the code
void
__libc_free(void *mem)
{
mchunkptr p;
/* 这里可以告诉你,可以不用手贱尝试释放NULL,你对我不起作用 */
if (mem == NULL) {
return;
}
p = (mchunkptr)((char *)mem - 2 * SIZE_SZ);
if (p->mchunk_size & IS_MAPPED) {
/* 动态调整threshold */
mp_.mmap_threshold = chunksize (p);
mp_.trim_threshold = 2 * mp_.mmap_threshold;
munmap_chunk(p);
return;
}
/* other code */
...
return;
}
static void
munmap_chunk(mchunkptr p)
{
size_t size = p->mchunk_size;
mp_.n_mmaps--;
mp_.mmaped_mem -= size;
/* 释放 */
munmap(p, size);
return;
}
两章总结
写了两篇东西了,也是时候写写总结
- 对于malloc来说,是分为三个调用层次,__libc_malloc,调用malloc_hook和包装层,_int_malloc是预处理层,并不涉及实际的调用内存分配接口,sysmalloc是实际分配内存的地方
- 小内存分配用sbrk分配一大块然后切割
- 大内存分配使用mmap/munmap进行管理
- sysmalloc的代码400+,两章已经差不多说完了,剩下的就是大头_int_malloc