victim = _int_malloc (ar_ptr, bytes); // 尝试分配内存(重要函数) /* Retry with another arena only if we were able to find a usable arena before. */ //如何没有找到合适的内存,就尝试找一个可用的arena(前提是 ar_ptr!=NULL),然后继续分配内存 if (!victim && ar_ptr != NULL) { LIBC_PROBE (memory_malloc_retry, 1, bytes); ar_ptr = arena_get_retry (ar_ptr, bytes); victim = _int_malloc (ar_ptr, bytes); }
/* 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分配,先进后出,比较的是无符号整数,这段代码可以在初始化堆之前运行 if ((unsignedlong) (nb) <= (unsignedlong) (get_max_fast ())) { idx = fastbin_index (nb); //得到对应fastbin大小的下标 mfastbinptr *fb = &fastbin (av, idx); //得到fastbin该大小的头指针 mchunkptr pp = *fb; do { // 如果fastbin中有chunk,后进先出取出来, victim = pp; if (victim == NULL) break; } while ((pp = catomic_compare_and_exchange_val_acq (fb, victim->fd, victim)) != victim); if (victim != 0) // victim不等于NULL,说明找到了chunk,检查后返回给用户 { // 检查chunk大小是否和前面确定的idx一样,防止被伪造 if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0)) { errstr = "malloc(): memory corruption (fast)"; errout: malloc_printerr (check_action, errstr, chunk2mem (victim), av); returnNULL; } check_remalloced_chunk (av, victim, nb); // 检查二次分配? void *p = chunk2mem (victim); alloc_perturb (p, bytes); return p; } }
/* 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.) */ // smallbin范围,先进先出 if (in_smallbin_range (nb)) // 是否在范围内 { idx = smallbin_index (nb); bin = bin_at (av, idx); // 这里是获取头吧 bin[x]这个东西?
/* 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. */ // 计算largebin的idx(仅仅是计算). 然后整理fastbin、检查有没有fastbin能够合并 else { idx = largebin_index (nb); if (have_fastchunks (av)) malloc_consolidate (av); }
/* 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) && // 用户请求的是smallbin大小 bck == unsorted_chunks (av) && //unsorted bin只有一个chunk victim == av->last_remainder && //且chunk为last_remainder??? (unsignedlong) (size) > (unsignedlong) (nb + MINSIZE)) // 并且满足拆分条件时,进行拆分 { /* split and reattach remainder */ remainder_size = size - nb; remainder = chunk_at_offset (victim, nb); unsorted_chunks (av)->bk = unsorted_chunks (av)->fd = remainder; av->last_remainder = remainder; remainder->bk = remainder->fd = unsorted_chunks (av); if (!in_smallbin_range (remainder_size)) { remainder->fd_nextsize = NULL; remainder->bk_nextsize = NULL; }
/* 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. */ // 进入largebin了... 不对..不是..这是啥 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 && //如果victim等于头结点,说明bin为空 (unsignedlong) (victim->size) >= (unsignedlong) (nb)) //小于nb,说明大小没有合适的 {//反向遍历bk_nextsize,从最小的大小开始,找到第一个不小于nb的chunk victim = victim->bk_nextsize; while (((unsignedlong) (size = chunksize (victim)) < (unsignedlong) (nb))) victim = victim->bk_nextsize; // 如果该chunk与victim的fd一样大,就选择fd chunk,避免改动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;