glibc-2.23学习笔记(二)—— free部分源码分析
生活随笔
收集整理的這篇文章主要介紹了
glibc-2.23学习笔记(二)—— free部分源码分析
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
glibc-2.23學(xué)習(xí)筆記(二)—— free部分源碼分析
- _libc_free
- _int_free
- 函數(shù)定義
- 局部變量
- start
- fast bins部分
- unsorted bins部分
- mmap部分
_libc_free
void __libc_free (void *mem) {mstate ar_ptr;mchunkptr p; /* chunk corresponding to mem *//* 判斷__free_hook中是否有值,若有值則將其當(dāng)作函數(shù)指針調(diào)用 */void (*hook) (void *, const void *)= atomic_forced_read (__free_hook);if (__builtin_expect (hook != NULL, 0)){(*hook)(mem, RETURN_ADDRESS (0));return;}/* 若需要回收的目標(biāo)指針為NULL,直接返回 */if (mem == 0) /* free(0) has no effect */return;/* 獲取用戶部分指針對(duì)應(yīng)的chunk頭的地址 */p = mem2chunk (mem);/* 若malloc_chunk->size字段的M位為1,表示當(dāng)前chunk是通過(guò)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); /* 釋放映射的內(nèi)存 */return;}/* 若chunk不是mmap映射的,則可能位于arena,因此嘗試獲取當(dāng)前chunk所屬的arena */ar_ptr = arena_for_chunk (p);_int_free (ar_ptr, p, 0); /* 調(diào)用_int_free */ } libc_hidden_def (__libc_free)_int_free
函數(shù)定義
static void _int_free(mstate av, mchunkptr p, int have_lock) {局部變量
/* 存儲(chǔ)size字段的值 */INTERNAL_SIZE_T size; /* its size *//* 存儲(chǔ)fast bin堆塊指針 */mfastbinptr* fb; /* associated fastbin *//* 下一個(gè)堆塊指針 */mchunkptr nextchunk; /* next contiguous chunk *//* 下一個(gè)堆塊大小 */INTERNAL_SIZE_T nextsize; /* its size *//* 下一個(gè)堆塊使用情況 */int nextinuse; /* true if nextchunk is used *//* 距離上一個(gè)堆塊距離 */INTERNAL_SIZE_T prevsize; /* size of previous contiguous chunk *//* 臨時(shí),bk指針指向的堆塊 */mchunkptr bck; /* misc temp for linking *//* 臨時(shí),fd指針指向的堆塊 */mchunkptr fwd; /* misc temp for linking */const char* errstr = NULL;int locked = 0;start
/* 獲取目標(biāo)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指針合法性,是否對(duì)齊等,不會(huì)影響性能 */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,以及是否對(duì)齊(第四個(gè)比特位是否為1(不能為1)) */if (__glibc_unlikely(size < MINSIZE || !aligned_OK(size))){errstr = "free(): invalid size";goto errout;}/* 判斷chunk是否處于空閑狀態(tài)(檢查下一個(gè)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*//* 如果設(shè)置了TRIM_FASTBINS,就不能將與top chunk相鄰的chunk放入fast bins */&& (chunk_at_offset(p, size) != av->top) #endif) {/* 檢查chunk大小,是否對(duì)齊 */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,一般無(wú)需關(guān)注 */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檢測(cè)(檢查當(dāng)前chunk是否為fast bins的最后一個(gè)成員) */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是通過(guò)mmap映射的(檢查M位)不是則執(zhí)行這一塊代碼chunk會(huì)進(jìn)入unsorted bins */else if (!chunk_is_mmapped(p)) {if (!have_lock) {(void)mutex_lock(&av->mutex);locked = 1;}/* 定位下一個(gè)chunk位置 */nextchunk = chunk_at_offset(p, size);/* Lightweight tests: check whether the block is already thetop block. *//* 如果申請(qǐng)釋放的堆塊為top chunk,觸發(fā)異常 */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. *//* 檢查下一個(gè)堆塊地址是否超過(guò)top chunk地址,超過(guò)則觸發(fā)異常 */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. *//* 若當(dāng)前堆塊已經(jīng)處于空閑狀態(tài),觸發(fā)異常 */if (__glibc_unlikely(!prev_inuse(nextchunk))){errstr = "double free or corruption (!prev)";goto errout;}/* 檢查size位大小是否合法與對(duì)齊情況 */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數(shù)據(jù) */free_perturb(chunk2mem(p), size - 2 * SIZE_SZ);/* consolidate backward *//* 若下一個(gè)chunk的p位也為1的話,則進(jìn)行Unlink,向上合并 */if (!prev_inuse(p)) {prevsize = p->prev_size;size += prevsize;p = chunk_at_offset(p, -((long)prevsize));unlink(av, p, bck, fwd);}/* 如果下一個(gè)chunk不是top chunk的話 */if (nextchunk != av->top) {/* get and clear inuse bit *//* 獲取下一個(gè)chunk p位的值 */nextinuse = inuse_bit_at_offset(nextchunk, nextsize);/* consolidate forward *//* 如果下一個(gè)chunk也處于空閑狀態(tài)的話,unlink,向下合并 */if (!nextinuse) {unlink(av, nextchunk, bck, fwd);size += nextsize;}else /* 否則將下一個(gè)chunk的p位置為0,表示當(dāng)前chunk已經(jīng)被釋放 */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; /* 指向最后一個(gè)進(jìn)入unsorted bins的指針 *//* 如果最后一個(gè)堆塊的bk不是指向bins的話,觸發(fā)異常 */if (__glibc_unlikely(fwd->bk != bck)){errstr = "free(): corrupted unsorted chunks";goto errout;}/* 將當(dāng)前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;/* 設(shè)置標(biāo)志位 */set_head(p, size | PREV_INUSE);set_foot(p, size);check_free_chunk(av, p); /* 包含各種檢測(cè) */}/*If the chunk borders the current high end of memory,consolidate into top*//* 如果當(dāng)前chunk是堆中的唯一一個(gè)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);/* 如果當(dāng)前arena為main_arena,且top chunk大小超過(guò)閾值,則切割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().*//* 不符合以上任何一種情況,直接解除內(nèi)存映射 */else {munmap_chunk(p);} }總結(jié)
以上是生活随笔為你收集整理的glibc-2.23学习笔记(二)—— free部分源码分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: glibc-2.23学习笔记(一)——
- 下一篇: Intel VT学习笔记(四)—— VM