glibc-2.23学习笔记(二)—— free部分源码分析

  • _libc_free
  • _int_free
    • 函数定义
    • 局部变量
    • start
    • fast bins部分
    • unsorted bins部分
    • mmap部分

_libc_free

void
__libc_free (void *mem)
{mstate ar_ptr;mchunkptr p;                          /* chunk corresponding to mem *//* 判断__free_hook中是否有值,若有值则将其当作函数指针调用 */void (*hook) (void *, const void *)= atomic_forced_read (__free_hook);if (__builtin_expect (hook != NULL, 0)){(*hook)(mem, RETURN_ADDRESS (0));return;}/* 若需要回收的目标指针为NULL,直接返回 */if (mem == 0)                              /* free(0) has no effect */return;/* 获取用户部分指针对应的chunk头的地址 */p = mem2chunk (mem);/* 若malloc_chunk->size字段的M位为1,表示当前chunk是通过mmap映射的 */if (chunk_is_mmapped (p))                       /* release mmapped memory. */{/* see if the dynamic brk/mmap threshold needs adjusting */if (!mp_.no_dyn_threshold&& p->size > mp_.mmap_threshold&& p->size <= DEFAULT_MMAP_THRESHOLD_MAX){mp_.mmap_threshold = chunksize (p);mp_.trim_threshold = 2 * mp_.mmap_threshold;LIBC_PROBE (memory_mallopt_free_dyn_thresholds, 2,mp_.mmap_threshold, mp_.trim_threshold);}munmap_chunk(p);  /* 释放映射的内存 */return;}/* 若chunk不是mmap映射的,则可能位于arena,因此尝试获取当前chunk所属的arena */ar_ptr = arena_for_chunk (p);_int_free (ar_ptr, p, 0);     /* 调用_int_free */
}
libc_hidden_def (__libc_free)

_int_free

函数定义

static void
_int_free(mstate av, mchunkptr p, int have_lock)
{

局部变量

 /* 存储size字段的值 */INTERNAL_SIZE_T size;        /* its size *//* 存储fast bin堆块指针 */mfastbinptr* fb;             /* associated fastbin *//* 下一个堆块指针 */mchunkptr nextchunk;         /* next contiguous chunk *//* 下一个堆块大小 */INTERNAL_SIZE_T nextsize;    /* its size *//* 下一个堆块使用情况 */int nextinuse;               /* true if nextchunk is used *//* 距离上一个堆块距离 */INTERNAL_SIZE_T prevsize;    /* size of previous contiguous chunk *//* 临时,bk指针指向的堆块 */mchunkptr bck;               /* misc temp for linking *//* 临时,fd指针指向的堆块 */mchunkptr fwd;               /* misc temp for linking */const char* errstr = NULL;int locked = 0;

start

 /* 获取目标chunk的size字段的值 */size = chunksize(p);/* Little security check which won't hurt performance: theallocator never wrapps around at the end of the address space.Therefore we can exclude some size values which might appearhere by accident or by "design" from some intruder.  *//* 安全检查,检查chunk指针合法性,是否对齐等,不会影响性能 */if (__builtin_expect((uintptr_t)p > (uintptr_t)-size, 0)|| __builtin_expect(misaligned_chunk(p), 0)){errstr = "free(): invalid pointer";errout:if (!have_lock && locked)(void)mutex_unlock(&av->mutex);malloc_printerr(check_action, errstr, chunk2mem(p), av);return;}/* We know that each chunk is at least MINSIZE bytes in size or amultiple of MALLOC_ALIGNMENT.  *//* 判断size字段是否小于chunk的最小size,以及是否对齐(第四个比特位是否为1(不能为1)) */if (__glibc_unlikely(size < MINSIZE || !aligned_OK(size))){errstr = "free(): invalid size";goto errout;}/* 判断chunk是否处于空闲状态(检查下一个chunk的p位) */check_inuse_chunk(av, p);

fast bins部分

    /*If eligible, place chunk on a fastbin so it can be foundand used quickly in malloc.*//* 判断chunk是否小于max_fast(0x80) */if ((unsigned long)(size) <= (unsigned long)(get_max_fast())#if TRIM_FASTBINS/*If TRIM_FASTBINS set, don't place chunksbordering top into fastbins*//* 如果设置了TRIM_FASTBINS,就不能将与top chunk相邻的chunk放入fast bins */&& (chunk_at_offset(p, size) != av->top)
#endif) {/* 检查chunk大小,是否对齐 */if (__builtin_expect(chunk_at_offset(p, size)->size <= 2 * SIZE_SZ, 0)|| __builtin_expect(chunksize(chunk_at_offset(p, size))>= av->system_mem, 0)){/* We might not have a lock at this point and concurrent modificationsof system_mem might have let to a false positive.  Redo the testafter getting the lock.  */if (have_lock|| ({ assert(locked == 0);mutex_lock(&av->mutex);locked = 1;chunk_at_offset(p, size)->size <= 2 * SIZE_SZ|| chunksize(chunk_at_offset(p, size)) >= av->system_mem;})){errstr = "free(): invalid next size (fast)";goto errout;}if (!have_lock){(void)mutex_unlock(&av->mutex);locked = 0;}}/* 特定条件下初始化memory,一般无需关注 */free_perturb(chunk2mem(p), size - 2 * SIZE_SZ);/* 将chunk放入fast bins中 */set_fastchunks(av);unsigned int idx = fastbin_index(size);fb = &fastbin(av, idx);/* Atomically link P to its fastbin: P->FD = *FB; *FB = P;  */mchunkptr old = *fb, old2;unsigned int old_idx = ~0u;do{/* Check that the top of the bin is not the record we are going to add(i.e., double free).  *//* double free检测(检查当前chunk是否为fast bins的最后一个成员) */if (__builtin_expect(old == p, 0)){errstr = "double free or corruption (fasttop)";goto errout;}/* Check that size of fastbin chunk at the top is the same assize of the chunk that we are adding.  We can dereference OLDonly if we have the lock, otherwise it might have already beendeallocated.  See use of OLD_IDX below for the actual check.  */if (have_lock && old != NULL)old_idx = fastbin_index(chunksize(old));p->fd = old2 = old;} while ((old = catomic_compare_and_exchange_val_rel(fb, p, old2)) != old2);if (have_lock && old != NULL && __builtin_expect(old_idx != idx, 0)){errstr = "invalid fastbin entry (free)";goto errout;}}

unsorted bins部分

    /*Consolidate other non-mmapped chunks as they arrive.*//* 如果chunk是通过mmap映射的(检查M位)不是则执行这一块代码chunk会进入unsorted bins */else if (!chunk_is_mmapped(p)) {if (!have_lock) {(void)mutex_lock(&av->mutex);locked = 1;}/* 定位下一个chunk位置 */nextchunk = chunk_at_offset(p, size);/* Lightweight tests: check whether the block is already thetop block.  *//* 如果申请释放的堆块为top chunk,触发异常 */if (__glibc_unlikely(p == av->top)){errstr = "double free or corruption (top)";goto errout;}/* Or whether the next chunk is beyond the boundaries of the arena.  *//* 检查下一个堆块地址是否超过top chunk地址,超过则触发异常 */if (__builtin_expect(contiguous(av)&& (char*)nextchunk>= ((char*)av->top + chunksize(av->top)), 0)){errstr = "double free or corruption (out)";goto errout;}/* Or whether the block is actually not marked used.  *//* 若当前堆块已经处于空闲状态,触发异常 */if (__glibc_unlikely(!prev_inuse(nextchunk))){errstr = "double free or corruption (!prev)";goto errout;}/* 检查size位大小是否合法与对齐情况 */nextsize = chunksize(nextchunk);if (__builtin_expect(nextchunk->size <= 2 * SIZE_SZ, 0)|| __builtin_expect(nextsize >= av->system_mem, 0)){errstr = "free(): invalid next size (normal)";goto errout;}/* 特定条件下初始化chunk数据 */free_perturb(chunk2mem(p), size - 2 * SIZE_SZ);/* consolidate backward *//* 若下一个chunk的p位也为1的话,则进行Unlink,向上合并 */if (!prev_inuse(p)) {prevsize = p->prev_size;size += prevsize;p = chunk_at_offset(p, -((long)prevsize));unlink(av, p, bck, fwd);}/* 如果下一个chunk不是top chunk的话 */if (nextchunk != av->top) {/* get and clear inuse bit *//* 获取下一个chunk p位的值 */nextinuse = inuse_bit_at_offset(nextchunk, nextsize);/* consolidate forward *//* 如果下一个chunk也处于空闲状态的话,unlink,向下合并 */if (!nextinuse) {unlink(av, nextchunk, bck, fwd);size += nextsize;}else    /* 否则将下一个chunk的p位置为0,表示当前chunk已经被释放 */clear_inuse_bit_at_offset(nextchunk, 0);/*Place the chunk in unsorted chunk list. Chunks arenot placed into regular bins until after they havebeen given one chance to be used in malloc.*//* 得到arena中bins指针 */bck = unsorted_chunks(av);fwd = bck->fd;    /* 指向最后一个进入unsorted bins的指针 *//* 如果最后一个堆块的bk不是指向bins的话,触发异常 */if (__glibc_unlikely(fwd->bk != bck)){errstr = "free(): corrupted unsorted chunks";goto errout;}/* 将当前chunk挂入unsorted bins */p->fd = fwd;p->bk = bck;if (!in_smallbin_range(size)) /* 若chunk属于Large bins范围,将fd_nextsize和bk_nextsize置为NULL */{p->fd_nextsize = NULL;p->bk_nextsize = NULL;}bck->fd = p;fwd->bk = p;/* 设置标志位 */set_head(p, size | PREV_INUSE);set_foot(p, size);check_free_chunk(av, p);  /* 包含各种检测 */}/*If the chunk borders the current high end of memory,consolidate into top*//* 如果当前chunk是堆中的唯一一个chunk,且位于堆地址顶部,则与top chunk合并 */else {size += nextsize;set_head(p, size | PREV_INUSE);av->top = p;check_chunk(av, p);}/*If freeing a large space, consolidate possibly-surroundingchunks. Then, if the total unused topmost memory exceeds trimthreshold, ask malloc_trim to reduce top.Unless max_fast is 0, we don't know if there are fastbinsbordering top, so we cannot tell for sure whether thresholdhas been reached unless fastbins are consolidated.  But wedon't want to consolidate on each free.  As a compromise,consolidation is performed if FASTBIN_CONSOLIDATION_THRESHOLDis reached.*//* 如果size字段的值大于65536,则合并堆中所有空闲的fast bin */if ((unsigned long)(size) >= FASTBIN_CONSOLIDATION_THRESHOLD) {if (have_fastchunks(av))malloc_consolidate(av);/* 如果当前arena为main_arena,且top chunk大小超过阈值,则切割arena */if (av == &main_arena) {#ifndef MORECORE_CANNOT_TRIMif ((unsigned long)(chunksize(av->top)) >=(unsigned long)(mp_.trim_threshold))systrim(mp_.top_pad, av);
#endif}else {/* Always try heap_trim(), even if the top chunk is notlarge, because the corresponding heap might go away.  *//* 不论如何,尝试切割堆 */heap_info* heap = heap_for_ptr(top(av));assert(heap->ar_ptr == av);heap_trim(heap, mp_.top_pad);}}/* 解除互斥锁 */if (!have_lock) {assert(locked);(void)mutex_unlock(&av->mutex);}}

mmap部分

    /*If the chunk was allocated via mmap, release via munmap().*//* 不符合以上任何一种情况,直接解除内存映射 */else {munmap_chunk(p);}
}

glibc-2.23学习笔记(二)—— free部分源码分析相关推荐

  1. Netty学习笔记(一)Netty客户端源码分析

    最近在学些BIO,NIO相关的知识,也学习了下Netty和它的源码,做个记录,方便以后继续学习,如果有错误的地方欢迎指正 如果不了解BIO,NIO这些基础知识,可以看下我的如下博客 IO中的阻塞.非阻 ...

  2. PCAP学习笔记二:pcap4j源码笔记

    环境 pcap4j:1.8.3 timeval org.pcap4j.core.NativeMappings.timeval,该类继承于com.sun.jna.Structure. 里面有两个主要字段 ...

  3. 【SLAM学习笔记】6-ORB_SLAM3关键源码分析④ Optimizer(一)单帧优化

    2021SC@SDUSC 目录 1.前言 2.代码分析 1.前言 Optimizer是非常重要的代码文件!! 这一部分代码量巨大,查阅了很多资料结合来看的代码,将分为以下部分进行分析 1. 单帧优化 ...

  4. Nginx学习笔记(五) 源码分析内存模块内存对齐

    Nginx源码分析&内存模块 今天总结了下C语言的内存分配问题,那么就看看Nginx的内存分配相关模型的具体实现.还有内存对齐的内容~~不懂的可以看看~~ src/os/unix/Ngx_al ...

  5. 【SLAM学习笔记】12-ORB_SLAM3关键源码分析⑩ Optimizer(七)地图融合优化

    2021SC@SDUSC 目录 1.前言 2.代码分析 1.前言 这一部分代码量巨大,查阅了很多资料结合来看的代码,将分为以下部分进行分析 单帧优化 局部地图优化 全局优化 尺度与重力优化 sim3优 ...

  6. 【SLAM学习笔记】11-ORB_SLAM3关键源码分析⑨ Optimizer(六)地图回环优化

    2021SC@SDUSC 目录 1.前言 2.代码分析 1.前言 这一部分代码量巨大,查阅了很多资料结合来看的代码,将分为以下部分进行分析 单帧优化 局部地图优化 全局优化 尺度与重力优化 sim3优 ...

  7. Android学习笔记-常用的一些源码,防止忘记了

    Android学习笔记-常用的一些源码,防止忘记了... 设置拨打电话 StringdialUri="tell:"+m_currentTelNumble; IntentcallIn ...

  8. Ceph 学习——OSD读写流程与源码分析(一)

    消息从客户端发送而来,之前几节介绍了 客户端下 对象存储.块存储库的实现以及他们在客户端下API请求的发送过程(Ceph学习--Librados与Osdc实现源码解析 . Ceph学习--客户端读写操 ...

  9. ActiveMQ学习笔记(8)——导入ActiveMQ源码到Eclipse

    2019独角兽企业重金招聘Python工程师标准>>> 一.准备 Eclipse Luna 版本,本身已经支持Git和Maven. 安装了apache-maven,我使用的是3.1. ...

  10. Java的wait()、notify()学习三部曲之一:JVM源码分析

    原文链接:https://blog.csdn.net/boling_cavalry/article/details/77793224 综述 Java的wait().notify()学习三部曲由三篇文章 ...

最新文章

  1. js高级程序设计笔记——DOM扩展
  2. A*算法 javascript模拟
  3. 配置Java_Home,临时环境变量信息
  4. Linux文件创建时间
  5. C++中如何初始化类中const或引用类型的数据成员?
  6. 明年的方向是JAVA+SAP
  7. java学习笔记_Java学习笔记day11
  8. nullnull使用PL/SQL获取创建用户的语句
  9. Controller计算值传到jsp页面,用session传值
  10. vue 属性 watch
  11. APP测试之使用ADB可能遇到的错误及解决办法
  12. H3C交换机MAC VLAN原理及配置示例
  13. org.apache.commons.fileupload.DiskFileUpload1
  14. MATLAB/simulink_S函数
  15. 华为数通考试正式改版,改版前后有什么区别?
  16. 值得思考:过去的中国大学
  17. nginx学习:搭建静态资源服务器
  18. 无人机协同搜索matlab,一种多无人机协同目标搜索方法与流程
  19. 集合易支付源码完美版
  20. VIEW: X$KSMLRU - LRU flushes from the shared pool - (7.3 - 8.1) [ID 43600.1]

热门文章

  1. ML之xgboost:利用xgboost算法(sklearn+3Split+调参曲线)训练mushroom蘑菇数据集(22+1,6513+1611)来预测蘑菇是否毒性(二分类预测)
  2. IDE之Eric:Python的IDE之eric的简介、安装、使用方法之详细攻略
  3. Py之PyTables:PyTables的简介、安装、使用方法详细攻略
  4. Python之tkinter:动态演示调用python库的tkinter带你进入GUI世界(LabelFrame/Checkbutton/Radiobutton)
  5. Anaconda:Anaconda安装图文教程及其tensorflow安装、运行、测试之最强详细攻略
  6. os_mbox.c(全)
  7. 读书不言迟,不读终身痴[转]
  8. document对象相关信息
  9. Classical Inheritance in JavaScript
  10. Go 1.4 正式版发布,官方正式支持 Android