您好,登錄后才能下訂單哦!
這篇文章主要介紹“l(fā)ibc2.23 malloc部分源碼分析”,在日常操作中,相信很多人在libc2.23 malloc部分源碼分析問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”libc2.23 malloc部分源碼分析”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
glibc 內(nèi)部 malloc() 函數(shù)只是__libc_malloc() 函數(shù)的別名,而 __libc_malloc() 函數(shù)的工作又主要由 _int_malloc() 完成。
因此,分析malloc() 函數(shù),
即是分析 __libc_malloc() 以及 _int_malloc() 這兩個(gè)函數(shù)。
2.24源碼
1.atomic_forced_read()函數(shù)
# define atomic_forced_read(x) ({ __typeof (x) __x; __asm ("" : "=r" (__x) : "0" (x)); __x; }) __typeof是原始函數(shù)的返回類(lèi)型,后面是一段匯編代碼,”0”是零,即%0,引用時(shí)不可以加 %, 只能input引用output,這里就是原子讀,將__malloc_hook的地址放入任意寄存器(r)再取出
2.關(guān)于malloc_hook的初始化問(wèn)題
ptmalloc 定義了一個(gè)全局鉤子 __malloc_hook,這個(gè)鉤子會(huì)被賦值為 malloc_hook_ini 函數(shù):(也就是說(shuō)剛開(kāi)始malloc_hook的值為malloc_hook_ini 函數(shù)的地址,第一次調(diào)用的時(shí)候會(huì)執(zhí)行malloc_hook_ini )
void *weak_variable (*__malloc_hook) (size_t __size, const void *) = malloc_hook_ini;
如果我們需要自定義堆分配函數(shù),那么就可以把 __malloc_hook 重新設(shè)置成我們自定義的函數(shù),在 __libc_malloc 的最開(kāi)始處會(huì)判斷是否調(diào)用 __malloc_hook。也就是說(shuō) ptmalloc 給我們提供了一個(gè)機(jī)會(huì)去使用自己定義的堆分配函數(shù)來(lái)完成對(duì)堆空間的申請(qǐng),申請(qǐng)完成后直接返回,如下:
void *(*hook) (size_t, const void *) = atomic_forced_read (__malloc_hook); if (__builtin_expect (hook != NULL, 0)) return (*hook)(bytes, RETURN_ADDRESS (0));
如果我們沒(méi)有自定義堆分配函數(shù),而是選擇默認(rèn)的 ptmalloc 來(lái)幫我們完成申請(qǐng),那么在用戶(hù)在第一次調(diào)用 malloc 函數(shù)時(shí)會(huì)首先轉(zhuǎn)入 malloc_hook_ini 函數(shù)里面,這個(gè)函數(shù)的定義在 hook.c 文件,如下:
static void * malloc_hook_ini (size_t sz, const void *caller) { __malloc_hook = NULL; ptmalloc_init (); return __libc_malloc (sz); }
可見(jiàn)在 malloc_hook_ini 會(huì)把 __malloc_hook 設(shè)置為空,然后調(diào)用 ptmalloc_init 函數(shù),這個(gè)函數(shù)的工作是完成對(duì) ptmalloc 的初始化,最后又重復(fù)調(diào)用 __libc_malloc 函數(shù)。
因此可知,在我們第一次調(diào)用 malloc 申請(qǐng)堆空間的時(shí)候,首先會(huì)進(jìn)入 malloc_hook_ini 函數(shù)里面進(jìn)行對(duì) ptmalloc 的初始化工作,然后再次進(jìn)入 __libc_malloc 的時(shí)候,此時(shí)鉤子 __malloc_hook 已經(jīng)被置空了,從而繼續(xù)執(zhí)行剩余的代碼,即轉(zhuǎn)入 _int_malloc 函數(shù)。
換個(gè)說(shuō)法,第一次調(diào)用 malloc 函數(shù)時(shí)函數(shù)調(diào)用路徑如下:
malloc -> __libc_malloc -> __malloc_hook(即malloc_hook_ini) -> ptmalloc_init -> __libc_malloc -> _int_malloc
以后用戶(hù)再調(diào)用 malloc 函數(shù)的時(shí)候,路徑將是這樣的:
malloc -> __libc_malloc -> _int_mallocc
3.ptmalloc_init 函數(shù)
ptmalloc_init 的定義在 arena.c 文件里面,它里面有這樣的一些操作:
static void ptmalloc_init (void) { if (__malloc_initialized >= 0) return; __malloc_initialized = 0; // 初始化 ptmalloc 操作 ... ... __malloc_initialized = 1; }
進(jìn)入 ptmalloc_init,首先判斷 __malloc_initialized 的值,__malloc_initialized 是一個(gè)全局變量,它標(biāo)記著 ptcmalloc 的初始化狀態(tài),如下:
>0 –> 初始化完成 =0 –> 正在初始化 <0 –> 尚未初始化
在 ptmalloc_init 中完成對(duì) ptmalloc 的初始化工作后,置 __malloc_initialized 為 1,表示 ptmalloc 已經(jīng)被初始化,之后再次進(jìn)入 ptmalloc_init 時(shí)就會(huì)直接退出,不會(huì)重復(fù)初始化。
4.之后對(duì)源碼的解釋
void * __libc_malloc (size_t bytes)//size_t bytes為我們用戶(hù)申請(qǐng)的大小 { mstate ar_ptr; void *victim; void *(*hook) (size_t, const void *) = atomic_forced_read (__malloc_hook); if (__builtin_expect (hook != NULL, 0)) return (*hook)(bytes, RETURN_ADDRESS (0)); arena_get (ar_ptr, bytes); //獲取當(dāng)前的arena,如果是主線(xiàn)程則獲得的是main_arena victim = _int_malloc (ar_ptr, bytes); //進(jìn)入_int_malloc函數(shù) /* Retry with another arena only if we were able to find a usable arena before. */ if (!victim && ar_ptr != NULL) //如果_int_malloc 分配失敗,并且我們之前能夠找到一個(gè)可用arena,可以用另一個(gè)arena重試。 { LIBC_PROBE (memory_malloc_retry, 1, bytes); ar_ptr = arena_get_retry (ar_ptr, bytes); victim = _int_malloc (ar_ptr, bytes); } if (ar_ptr != NULL) (void) mutex_unlock (&ar_ptr->mutex); //釋放mutex引用的互斥鎖對(duì)象,因?yàn)閜tmalloc支持多線(xiàn)程 assert (!victim || chunk_is_mmapped (mem2chunk (victim)) || ar_ptr == arena_for_chunk (mem2chunk (victim))); return victim; } libc_hidden_def (__libc_malloc)
/* ------------------------------ malloc ------------------------------ */ static void * _int_malloc (mstate av, size_t bytes) { INTERNAL_SIZE_T nb; /* normalized request size */ unsigned int idx; /* associated bin index */ mbinptr bin; /* associated bin */ mchunkptr victim; /* inspected/selected chunk */ INTERNAL_SIZE_T size; /* its size */ int victim_index; /* its bin index */ mchunkptr remainder; /* remainder from a split */ unsigned long remainder_size; /* its size */ unsigned int block; /* bit map traverser */ unsigned int bit; /* bit map traverser */ unsigned int map; /* current word of binmap */ mchunkptr fwd; /* misc temp for linking */ mchunkptr bck; /* misc temp for linking */ const char *errstr = NULL; /* Convert request size to internal form by adding SIZE_SZ bytes overhead plus possibly more to obtain necessary alignment and/or to obtain a size of at least MINSIZE, the smallest allocatable size. Also, checked_request2size traps (returning 0) request sizes that are so large that they wrap around zero when padded and aligned. */ checked_request2size (bytes, nb); //這里將我們用戶(hù)申請(qǐng)的大小轉(zhuǎn)化為對(duì)應(yīng)chunk的大小,nb就是我們轉(zhuǎn)化后的大小 /* There are no usable arenas. Fall back to sysmalloc to get a chunk from mmap. */ if (__glibc_unlikely (av == NULL)) { void *p = sysmalloc (nb, av); if (p != NULL) alloc_perturb (p, bytes); return p; } ////傳入的參數(shù)av是在上面__libc_malloc中調(diào)用arena_get獲得的分配去指針,如果為null,就表示沒(méi)有分配區(qū)可用,這時(shí)候就直接調(diào)用sysmalloc通過(guò)mmap獲取chunk /* If the size qualifies as a fastbin, first check corresponding bin. This code is safe to execute even if av is not yet initialized, so we can try it without checking, which saves some time on this fast path. */ //從 fastbin 中分配 chunk if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ())) //get_max_fast返回fastbin可以存儲(chǔ)內(nèi)存的最大值,它在ptmalloc的初始化函數(shù)malloc_init_state中定義。 //如果需要分配的內(nèi)存大小nb落在fastbin的范圍內(nèi),我么嘗試從 fast bins 中 分配 chunk { idx = fastbin_index (nb); /* 加入我們的chunk大小是0x20(最小也是0x20),那么我們的索引就是(64位) 1.0x20 >> 4 = 2 2.2 -2 = 0 3.idx = 0 #define fastbin_index(sz) ((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2) 減2是根據(jù)fastbin存儲(chǔ)的內(nèi)存最小值計(jì)算的,32位為4,64位為8,假設(shè)SIZE_SZ=8,因此改寫(xiě)后 idx = (nb>>4)-2 */ mfastbinptr *fb = &fastbin (av, idx); //#define fastbin(ar_ptr, idx) ((ar_ptr)->fastbinsY[idx]) //根據(jù)idx獲取對(duì)應(yīng)鏈表的頭指針 mchunkptr pp = *fb;//獲取對(duì)應(yīng)大小的fatbin的鏈表中的第一個(gè)空閑的chunk do { victim = pp; if (victim == NULL) break; } while ((pp = catomic_compare_and_exchange_val_acq (fb, victim->fd, victim)) != victim); //catomic_compare_and_exchange_val_rel 功能是 如果*fb等于victim,則將*fb存儲(chǔ)為victim->fd,返回victim; //pp = victim == victim 導(dǎo)致循環(huán)退出 //作用為從剛剛得到的空閑chunk鏈表指針中取出第一個(gè)空閑的chunk(victim),并將鏈表頭設(shè)置為該空閑chunk的下一個(gè)chunk(victim->fd) //此時(shí)victim是我們?nèi)〕龅腸hunk的地址 if (victim != 0) { if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0)) //這里是檢查我們?nèi)〕龅腸hunk的size所對(duì)應(yīng)的索引是否等于我們之前已經(jīng)得到的索引 //其實(shí)這里就是在檢查我們?nèi)〕龅腸hunk的size是否與我們申請(qǐng)的fastbin的大小相同(這也是malloc的唯一檢查) { errstr = "malloc(): memory corruption (fast)"; errout: malloc_printerr (check_action, errstr, chunk2mem (victim), av); return NULL; } check_remalloced_chunk (av, victim, nb); ////# define check_remalloced_chunk(A, P, N) //check_remalloced_chunk 這個(gè)函數(shù)其他博客說(shuō)什么也沒(méi)有實(shí)現(xiàn) void *p = chunk2mem (victim);//把chunk的指針轉(zhuǎn)換成mem的指針 alloc_perturb (p, bytes); /* static void alloc_perturb (char *p, size_t n) { if (__glibc_unlikely (perturb_byte)) memset (p, perturb_byte ^ 0xff, n); } */ /*這里就是向p(chunk的地址)+0x10填充字符(大小是我們申請(qǐng)的大小),但是貌似 啥時(shí)候填充不知到,,就直接忽略把,其實(shí)啥也沒(méi)有發(fā)生*/ return p;//反回我們的chunk } } /* If a small request, check regular bin. Since these "smallbins" hold one size each, no searching within bins is necessary. (For a large request, we need to wait until unsorted chunks are processed to find best fit. But for small ones, fits are exact anyway, so we can check now, which is faster.) */ //如果在 fastbins 里面沒(méi)有找到滿(mǎn)足要求的空閑 chunk 或者 nb 不屬于 fastbins,并且 nb 屬于 smallbins if (in_smallbin_range (nb)) { idx = smallbin_index (nb); /* #define smallbin_index(sz) ( (SMALLBIN_WIDTH == 16 ? (((unsigned) (sz)) >> 4) : (((unsigned) (sz)) >> 3)) ) 如果是64位,size>>4就是smallbin_index,32位則是size>>3 */ //idx為獲取的索引指針 bin = bin_at (av, idx); //獲得索引idx后,就通過(guò)idx獲取對(duì)應(yīng)的small bin鏈表表頭指針 if ((victim = last (bin)) != bin) //獲取對(duì)應(yīng)鏈表的最后一個(gè)chunk為victim然后與bin進(jìn)行比較,也就是和鏈表頭進(jìn)行比較,如果比較的結(jié)果為相等,那么該鏈表為空,跳過(guò)下面部分,進(jìn)入檢查整理unsorted bin的行列,若不相等,則進(jìn)入下面的代碼 { if (victim == 0) /* initialization check */ //victim為0表示smallbin還未初始化 malloc_consolidate (av);//調(diào)用malloc_consolidate完成初始化操作 else { bck = victim->bk; //獲取此chunk的下一個(gè)chunk的地址 if (__glibc_unlikely (bck->fd != victim))//small bin 采取先進(jìn)先出的原則 //這里檢查victim下一個(gè)chunk的fd是否與victim相等 //這里也是small bin的唯一檢查 { errstr = "malloc(): smallbin double linked list corrupted"; goto errout; } set_inuse_bit_at_offset (victim, nb); /* #define set_inuse(p) \ ((mchunkptr) (((char *) (p)) + ((p)->size & ~SIZE_BITS)))->size |= PREV_INUSE */ //此函數(shù)為將下一個(gè)物理地址相鄰的chunk的 inuse bit 為 1 //size & ~SIZE_BITS,這個(gè)為size大小去掉標(biāo)志位的結(jié)果,得到(p + (p)->size & ~SIZE_BITS))也就是說(shuō)獲取相鄰物理地址下一個(gè)chunk的地址 bin->bk = bck; bck->fd = bin; //雙向鏈表 bin->bk = bck;鏈表頭的bk為victim下一個(gè)chunk的地址 // bck->fd = bin victim下一個(gè)chunk的fd設(shè)置為鏈表頭地址 if (av != &main_arena) victim->size |= NON_MAIN_ARENA;//如果不是主線(xiàn)程則設(shè)置NON_MAIN_ARENA位 check_malloced_chunk (av, victim, nb);//默認(rèn)沒(méi)有做任何操作 void *p = chunk2mem (victim);//這里就和之前相同了將chunk指針轉(zhuǎn)化為mem指針 alloc_perturb (p, bytes);//默認(rèn)不做任何操作 return p; } } } /* If this is a large request, consolidate fastbins before continuing. While it might look excessive to kill all fastbins before even seeing if there is space available, this avoids fragmentation problems normally associated with fastbins. Also, in practice, programs tend to have runs of either small or large requests, but less often mixtures, so consolidation is not invoked all that often in most programs. And the programs that it is called frequently in otherwise tend to fragment. */ else//這里就是我們申請(qǐng)的大小屬于large bin { idx = largebin_index (nb);//獲取對(duì)應(yīng)大小的large bin的索引 if (have_fastchunks (av))//這里是檢查fastbin鏈表是否為空,若為空就沒(méi)必要執(zhí)行malloc_consolidate (av);來(lái)合并fastbin了,如果不為空則執(zhí)行malloc_consolidate (av) //標(biāo)記 fastbins 是否為空的是分配區(qū)管理的一個(gè)數(shù)據(jù)成員 flags,在 free 函數(shù)中當(dāng)被釋放空間插入到 fastbins 中時(shí)這個(gè)數(shù)據(jù)成員被設(shè)置,在 malloc_consolidate 函數(shù)中整理 fastbins 時(shí)這個(gè)數(shù)據(jù)成員被清除。 /* #define FASTCHUNKS_BIT (1U) #define have_fastchunks(M) (((M)->flags & FASTCHUNKS_BIT) == 0) */ malloc_consolidate (av); } //malloc_consolidate (av);函數(shù): /*fastbins中的chunk都整理到unsortedbin中,整理的過(guò)程中如果有物理相鄰且空閑的fastchunk就合并,如果fastchunk與topchunk相鄰,那么fastchunk就與topchunk合并(這個(gè)過(guò)程發(fā)生在_int_malloc函數(shù)調(diào)用的malloc_consolidate函數(shù)中) (注意這里是把fastbin中的所有塊清空)*/ /* Process recently freed or remaindered chunks, taking one only if it is exact fit, or, if this a small request, the chunk is remainder from the most recent non-exact fit. Place other traversed chunks in bins. Note that this step is the only place in any routine where chunks are placed in bins. The outer loop here is needed because we might not realize until near the end of malloc that we should have consolidated, so must do so and retry. This happens at most once, and only when we would otherwise need to expand memory to service a "small" request. */ for (;; ) { int iters = 0; while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av)) //如果沒(méi)有鏈表為空,那么unsorted_chunks (av)->bk) = unsorted_chunks (av) = main_arnea中的top //如果鏈表不為空,則循環(huán)遍歷所有的chunk { bck = victim->bk; if (__builtin_expect (victim->size <= 2 * SIZE_SZ, 0) || __builtin_expect (victim->size > av->system_mem, 0)) malloc_printerr (check_action, "malloc(): memory corruption", chunk2mem (victim), av); size = chunksize (victim); /* 檢查當(dāng)前遍歷的 chunk 是否合法,chunk 的大小不能小于等于 2 * SIZE_SZ, 也不能超過(guò) 該分配區(qū)總的內(nèi)存分配量。然后獲取 chunk 的大小并賦值給 size。 這里的檢查似乎有點(diǎn)小問(wèn) 題,直接使用了 victim->size,但 victim->size 中包含了相關(guān)的標(biāo)志位信息,使用 chunksize(victim) 才比較合理,但在 unsorted bin 中的空閑 chunk 的所有標(biāo)志位都清零了,所以這里直接 victim->size 沒(méi)有問(wèn)題。 */ /* If a small request, try to use last remainder if it is the only chunk in unsorted bin. This helps promote locality for runs of consecutive small requests. This is the only exception to best-fit, and applies only when there is no exact fit for a small chunk. */ if (in_smallbin_range (nb) && bck == unsorted_chunks (av) && victim == av->last_remainder && (unsigned long) (size) > (unsigned long) (nb + MINSIZE)) /* 如果要申請(qǐng)的大小在smallbin范圍 且 unsorted chunks 只有一個(gè)chunk,且 victim是last_remainder 且 victim的size大于請(qǐng)求的chunk的大小nb加上 (MINSIZE)最小chunk的size,那么就切割remainder,然后返回victim。 即滿(mǎn)足四個(gè)條件: 申請(qǐng)空間 nb 在 smallbins 范圍內(nèi) unsortedbin 僅有唯一一個(gè)空閑 chunk 唯一的一個(gè)空閑 chunk 是 last_remainder 唯一一個(gè)空閑 chunk 的大小可以進(jìn)行切割 如果在bins鏈(不包括fastbin)中存在freechunk時(shí),當(dāng)我們?nèi)alloc的時(shí)候,malloc的請(qǐng)求大小比f(wàn)reechunk的大小小,那么arena就會(huì)切割這個(gè)freechunk給malloc使用,那么切割之后剩余的chunk就被稱(chēng)為“l(fā)ast remainder” 當(dāng)產(chǎn)生last remainder之后,表示arena的malloc_state結(jié)構(gòu)體中的last_remainder成員指針就會(huì)被初始化,并且指向這個(gè)last remainder */ { /* split and reattach remainder */ //分割reminder,并將新的reminder插入到unsorted bin中 remainder_size = size - nb;//計(jì)算剩下reminder的大小 remainder = chunk_at_offset (victim, nb);//獲取剩下的reminder的地址 unsorted_chunks (av)->bk = unsorted_chunks (av)->fd = remainder;//將新的reminder插入到unsorted bin中 av->last_remainder = remainder;//last_reminder重新指向新的reminder remainder->bk = remainder->fd = unsorted_chunks (av);//新reminder的fd與bk指向unsorted bin 的鏈表頭,注意,unsorted bin鏈表頭并不是malloc_chunk結(jié)構(gòu)體,而是main_arena變量中bins列表的前兩項(xiàng)分別做fd和bk指針,指向的位置也不是pre_size,而是main_arena中的top,top指向top chunk。 if (!in_smallbin_range (remainder_size)) //如果新的remind的size不在small bin中,而是在large bin中,那么將則把 fd_nextsize,fd_nextsize清零 { remainder->fd_nextsize = NULL; remainder->bk_nextsize = NULL; } set_head (victim, nb | PREV_INUSE | (av != &main_arena ? NON_MAIN_ARENA : 0));//設(shè)置victim的size set_head (remainder, remainder_size | PREV_INUSE);//設(shè)置remainder的size set_foot (remainder, remainder_size);//設(shè)置remainder的物理相鄰的下一個(gè)chunk的prev_size check_malloced_chunk (av, victim, nb);///默認(rèn)沒(méi)有做任何操作 void *p = chunk2mem (victim);//這里就和之前相同了將chunk指針轉(zhuǎn)化為mem指針 alloc_perturb (p, bytes);//默認(rèn)沒(méi)有做任何操作 return p; } /* remove from unsorted list */ unsorted_chunks (av)->bk = bck; bck->fd = unsorted_chunks (av); //將victim移除unsorted bin /* Take now instead of binning if exact fit */ //下面是精確匹配,如果我們申請(qǐng)的大小轉(zhuǎn)化后正好等于victim size,直接返回即可 if (size == nb) { set_inuse_bit_at_offset (victim, size); //設(shè)置victim物理相鄰的下一個(gè)chunk的prev_inuse位 if (av != &main_arena) victim->size |= NON_MAIN_ARENA; //如果av不是main_arena 也就是說(shuō)如果不是主進(jìn)程,設(shè)置NON_MAIN_ARENA位 check_malloced_chunk (av, victim, nb);//默認(rèn)不做任何操作 void *p = chunk2mem (victim);//這里就和之前相同了將chunk指針轉(zhuǎn)化為mem指針 alloc_perturb (p, bytes);//默認(rèn)不做任何操作 return p; } /* place chunk in bin */ //若上一個(gè)步驟沒(méi)有成功,則將victim置于對(duì)應(yīng)的bin中 if (in_smallbin_range (size))//如果victim的size大小為small bin { victim_index = smallbin_index (size);//獲取大小對(duì)應(yīng)的索引 bck = bin_at (av, victim_index);//宏 bin_at(m, i) 通過(guò) bin index 獲得 bin 的鏈表頭,m 指的是分配區(qū),i 是索引 fwd = bck->fd;//FIFO原則 bck->fd 指向最新插入的chunk(small bin為頭插法) } else//若不在small bin的范圍中,則 { victim_index = largebin_index (size); bck = bin_at (av, victim_index); fwd = bck->fd;//FIFO原則 bck->fd 指向最新插入的chunk(small bin為頭插法) /* maintain large bins in sorted order */ if (fwd != bck) { /* Or with inuse bit to speed comparisons */ size |= PREV_INUSE; /* if smaller than smallest, bypass loop below */ assert ((bck->bk->size & NON_MAIN_ARENA) == 0); if ((unsigned long) (size) < (unsigned long) (bck->bk->size)) { fwd = bck; bck = bck->bk; victim->fd_nextsize = fwd->fd; victim->bk_nextsize = fwd->fd->bk_nextsize; fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim; } else { assert ((fwd->size & NON_MAIN_ARENA) == 0); while ((unsigned long) size < fwd->size) { fwd = fwd->fd_nextsize; assert ((fwd->size & NON_MAIN_ARENA) == 0); } if ((unsigned long) size == (unsigned long) fwd->size) /* Always insert in the second position. */ fwd = fwd->fd; else { victim->fd_nextsize = fwd; victim->bk_nextsize = fwd->bk_nextsize; fwd->bk_nextsize = victim; victim->bk_nextsize->fd_nextsize = victim; } bck = fwd->bk; } } else victim->fd_nextsize = victim->bk_nextsize = victim; } mark_bin (av, victim_index); victim->bk = bck; victim->fd = fwd; fwd->bk = victim; bck->fd = victim; #define MAX_ITERS 10000 if (++iters >= MAX_ITERS) break; } /* If a large request, scan through the chunks of current bin in sorted order to find smallest that fits. Use the skip list for this. */ if (!in_smallbin_range (nb)) { bin = bin_at (av, idx); /* skip scan if empty or largest chunk is too small */ if ((victim = first (bin)) != bin && (unsigned long) (victim->size) >= (unsigned long) (nb)) { victim = victim->bk_nextsize; while (((unsigned long) (size = chunksize (victim)) < (unsigned long) (nb))) victim = victim->bk_nextsize; /* Avoid removing the first entry for a size so that the skip list does not have to be rerouted. */ if (victim != last (bin) && victim->size == victim->fd->size) victim = victim->fd; remainder_size = size - nb; unlink (av, victim, bck, fwd); /* Exhaust */ if (remainder_size < MINSIZE) { set_inuse_bit_at_offset (victim, size); if (av != &main_arena) victim->size |= NON_MAIN_ARENA; } /* Split */ else { remainder = chunk_at_offset (victim, nb); /* We cannot assume the unsorted list is empty and therefore have to perform a complete insert here. */ bck = unsorted_chunks (av); fwd = bck->fd; if (__glibc_unlikely (fwd->bk != bck)) { errstr = "malloc(): corrupted unsorted chunks"; goto errout; } remainder->bk = bck; remainder->fd = fwd; bck->fd = remainder; fwd->bk = remainder; if (!in_smallbin_range (remainder_size)) { remainder->fd_nextsize = NULL; remainder->bk_nextsize = NULL; } set_head (victim, nb | PREV_INUSE | (av != &main_arena ? NON_MAIN_ARENA : 0)); set_head (remainder, remainder_size | PREV_INUSE); set_foot (remainder, remainder_size); } check_malloced_chunk (av, victim, nb); void *p = chunk2mem (victim); alloc_perturb (p, bytes); return p; } } /* Search for a chunk by scanning bins, starting with next largest bin. This search is strictly by best-fit; i.e., the smallest (with ties going to approximately the least recently used) chunk that fits is selected. The bitmap avoids needing to check that most blocks are nonempty. The particular case of skipping all bins during warm-up phases when no chunks have been returned yet is faster than it might look. */ ++idx; bin = bin_at (av, idx); block = idx2block (idx); map = av->binmap[block]; bit = idx2bit (idx); for (;; ) { /* Skip rest of block if there are no more set bits in this block. */ if (bit > map || bit == 0) { do { if (++block >= BINMAPSIZE) /* out of bins */ goto use_top; } while ((map = av->binmap[block]) == 0); bin = bin_at (av, (block << BINMAPSHIFT)); bit = 1; } /* Advance to bin with set bit. There must be one. */ while ((bit & map) == 0) { bin = next_bin (bin); bit <<= 1; assert (bit != 0); } /* Inspect the bin. It is likely to be non-empty */ victim = last (bin); /* If a false alarm (empty bin), clear the bit. */ if (victim == bin) { av->binmap[block] = map &= ~bit; /* Write through */ bin = next_bin (bin); bit <<= 1; } else { size = chunksize (victim); /* We know the first chunk in this bin is big enough to use. */ assert ((unsigned long) (size) >= (unsigned long) (nb)); remainder_size = size - nb; /* unlink */ unlink (av, victim, bck, fwd); /* Exhaust */ if (remainder_size < MINSIZE) { set_inuse_bit_at_offset (victim, size); if (av != &main_arena) victim->size |= NON_MAIN_ARENA; } /* Split */ else { remainder = chunk_at_offset (victim, nb); /* We cannot assume the unsorted list is empty and therefore have to perform a complete insert here. */ bck = unsorted_chunks (av); fwd = bck->fd; if (__glibc_unlikely (fwd->bk != bck)) { errstr = "malloc(): corrupted unsorted chunks 2"; goto errout; } remainder->bk = bck; remainder->fd = fwd; bck->fd = remainder; fwd->bk = remainder; /* advertise as last remainder */ if (in_smallbin_range (nb)) av->last_remainder = remainder; if (!in_smallbin_range (remainder_size)) { remainder->fd_nextsize = NULL; remainder->bk_nextsize = NULL; } set_head (victim, nb | PREV_INUSE | (av != &main_arena ? NON_MAIN_ARENA : 0)); set_head (remainder, remainder_size | PREV_INUSE); set_foot (remainder, remainder_size); } check_malloced_chunk (av, victim, nb); void *p = chunk2mem (victim); alloc_perturb (p, bytes); return p; } } use_top: /* If large enough, split off the chunk bordering the end of memory (held in av->top). Note that this is in accord with the best-fit search rule. In effect, av->top is treated as larger (and thus less well fitting) than any other available chunk since it can be extended to be as large as necessary (up to system limitations). We require that av->top always exists (i.e., has size >= MINSIZE) after initialization, so if it would otherwise be exhausted by current request, it is replenished. (The main reason for ensuring it exists is that we may need MINSIZE space to put in fenceposts in sysmalloc.) */ victim = av->top; size = chunksize (victim); if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE)) { remainder_size = size - nb; remainder = chunk_at_offset (victim, nb); av->top = remainder; set_head (victim, nb | PREV_INUSE | (av != &main_arena ? NON_MAIN_ARENA : 0)); set_head (remainder, remainder_size | PREV_INUSE); check_malloced_chunk (av, victim, nb); void *p = chunk2mem (victim); alloc_perturb (p, bytes); return p; } /* When we are using atomic ops to free fast chunks we can get here for all block sizes. */ else if (have_fastchunks (av)) { malloc_consolidate (av); /* restore original bin index */ if (in_smallbin_range (nb)) idx = smallbin_index (nb); else idx = largebin_index (nb); } /* Otherwise, relay to handle system-dependent cases */ else { void *p = sysmalloc (nb, av); if (p != NULL) alloc_perturb (p, bytes); return p; } } }
到此,關(guān)于“l(fā)ibc2.23 malloc部分源碼分析”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。