使われていないファーストビンのチャンクは、他のチャンクと合成することで解放することができます。
チャンクを合成する場合は 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