使われていないファーストビンのチャンクは、他のチャンクと合成することで解放することができます。
チャンクを合成する場合は malloc_consolidate() 関数をコールします。
malloc.c(https://github.com/MacKomatsu/glibc/blob/release/2.27/master/malloc/malloc.c).
1003 struct malloc_chunk;
1004 typedef struct malloc_chunk* mchunkptr;
1587 typedef struct malloc_chunk *mfastbinptr;
1588 #define fastbin(ar_ptr, idx) ((ar_ptr)->fastbinsY[idx])
4392 /*
4393 ------------------------- malloc_consolidate -------------------------
4394
4395 malloc_consolidate is a specialized version of free() that tears
4396 down chunks held in fastbins. Free itself cannot be used for this
4397 purpose since, among other things, it might place chunks back onto
4398 fastbins. So, instead, we need to use a minor variant of the same
4399 code.
4400 */
4401
4402 static void malloc_consolidate(mstate av)
4403 {
4404 mfastbinptr* fb; /* current fastbin being consolidated */
4405 mfastbinptr* maxfb; /* last fastbin (for loop control) */
4406 mchunkptr p; /* current chunk being consolidated */
4407 mchunkptr nextp; /* next chunk to consolidate */
4408 mchunkptr unsorted_bin; /* bin header */
4409 mchunkptr first_unsorted; /* chunk to link to */
4410
4411 /* These have same use as in free() */
4412 mchunkptr nextchunk;
4413 INTERNAL_SIZE_T size;
4414 INTERNAL_SIZE_T nextsize;
4415 INTERNAL_SIZE_T prevsize;
4416 int nextinuse;
4417 mchunkptr bck;
4418 mchunkptr fwd;
4419
4420 atomic_store_relaxed (&av->have_fastchunks, false);
4421
4422 unsorted_bin = unsorted_chunks(av);
4423
4424 /*
4425 Remove each chunk from fast bin and consolidate it, placing it
4426 then in unsorted bin. Among other reasons for doing this,
4427 placing in unsorted bin avoids needing to calculate actual bins
4428 until malloc is sure that chunks aren't immediately going to be
4429 reused anyway.
4430 */
4431
4432 maxfb = &fastbin (av, NFASTBINS - 1);
4433 fb = &fastbin (av, 0);
4434 do {
4435 p = atomic_exchange_acq (fb, NULL);
4436 if (p != 0) {
4437 do {
4438 {
4439 unsigned int idx = fastbin_index (chunksize (p));
4440 if ((&fastbin (av, idx)) != fb)
4441 malloc_printerr ("malloc_consolidate(): invalid chunk size");
4442 }
4443
4444 check_inuse_chunk(av, p);
4445 nextp = p->fd;
4446
4447 /* Slightly streamlined version of consolidation code in free() */
4448 size = chunksize (p);
4449 nextchunk = chunk_at_offset(p, size);
4450 nextsize = chunksize(nextchunk);
4451
4452 if (!prev_inuse(p)) {
4453 prevsize = prev_size (p);
4454 size += prevsize;
4455 p = chunk_at_offset(p, -((long) prevsize));
4456 unlink(av, p, bck, fwd);
4457 }
4458
4459 if (nextchunk != av->top) {
4460 nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
4461
4462 if (!nextinuse) {
4463 size += nextsize;
4464 unlink(av, nextchunk, bck, fwd);
4465 } else
4466 clear_inuse_bit_at_offset(nextchunk, 0);
4467
4468 first_unsorted = unsorted_bin->fd;
4469 unsorted_bin->fd = p;
4470 first_unsorted->bk = p;
4471
4472 if (!in_smallbin_range (size)) {
4473 p->fd_nextsize = NULL;
4474 p->bk_nextsize = NULL;
4475 }
4476
4477 set_head(p, size | PREV_INUSE);
4478 p->bk = unsorted_bin;
4479 p->fd = first_unsorted;
4480 set_foot(p, size);
4481 }
4482
4483 else {
4484 size += nextsize;
4485 set_head(p, size | PREV_INUSE);
4486 av->top = p;
4487 }
4488
4489 } while ( (p = nextp) != 0);
4490
4491 }
4492 } while (fb++ != maxfb);
4493 }
まずは fb のポインターを NULL と交換してチャンク p をゲットします。
4432 maxfb = &fastbin (av, NFASTBINS - 1);
4433 fb = &fastbin (av, 0);
4434 do {
4435 p = atomic_exchange_acq (fb, NULL);
4436 if (p != 0) {
4437 do {
//中略
4444 check_inuse_chunk(av, p);
4445 nextp = p->fd;
//中略
4489 } while ( (p = nextp) != 0);
4490
4491 }
4492 } while (fb++ != maxfb);これによりファーストビンでループを回します。
内部ループとして p が 0 に評価されるなら次のループに移行します。
前のチャンクが使用されていない場合は unlink() マクロをコールします。
4452 if (!prev_inuse(p)) {
4453 prevsize = prev_size (p);
4454 size += prevsize;
4455 p = chunk_at_offset(p, -((long) prevsize));
4456 unlink(av, p, bck, fwd);
4457 }次のチャンク(nextchunk)がトップチャンクでなく、次のチャンクが使用されていない場合は unlink() マクロをコールします
4459 if (nextchunk != av->top) {
4460 nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
4461
4462 if (!nextinuse) {
4463 size += nextsize;
4464 unlink(av, nextchunk, bck, fwd);
4465 } else
4466 clear_inuse_bit_at_offset(nextchunk, 0);続けて、前のチャンクとマージします。
4468 first_unsorted = unsorted_bin->fd;
4469 unsorted_bin->fd = p;
4470 first_unsorted->bk = p;
4471
4472 if (!in_smallbin_range (size)) {
4473 p->fd_nextsize = NULL;
4474 p->bk_nextsize = NULL;
4475 }
4476
4477 set_head(p, size | PREV_INUSE);
4478 p->bk = unsorted_bin;
4479 p->fd = first_unsorted;
4480 set_foot(p, size);後は合成したチャンクを未整理ビン( Unsorted Bin )のヘッドに追加するだけです。
もし次のチャンク(nextchunk)がトップチャンクであるなら、トップチャンクにマージします。
4483 else {
4484 size += nextsize;
4485 set_head(p, size | PREV_INUSE);
4486 av->top = p;
4487 }この場合は単にチャンク p のヘッドサイズを変更して、トップチャンクに設定しているだけです。
Copyright 2018-2019, by Masaki Komatsu