glibc-2.23学习笔记(二)—— free部分源码分析
生活随笔
收集整理的這篇文章主要介紹了
glibc-2.23学习笔记(二)—— free部分源码分析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
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部分源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: glibc-2.23学习笔记(一)——
- 下一篇: Intel VT学习笔记(四)—— VM