[Week06][C] Malloc-lab

Pyotatoยท2023๋…„ 5์›” 17์ผ
1

[C์–ธ์–ด]

๋ชฉ๋ก ๋ณด๊ธฐ
4/5
post-thumbnail

๐Ÿ‘ฉโ€๐Ÿ’ปDynamic Memory Allocation in the Heap : Malloc & free
(ํž™๊ณต๊ฐ„์—์„œ์˜ ๋™์ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น)
๐Ÿ‘ฉโ€๐Ÿ’ปcomputer systems 9์žฅ
๐Ÿ‘ฉโ€๐Ÿ’ป implicit list , explicit list & seglist allocator

1. Heap Allocation

  • ๋ฉ”๋ชจ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ์ถ”์ƒํ™”ํ•œ ๊ฑฐ๋ฅผ ๋ณด๋ฉด [์Šคํƒ]-[ํž™]-[์ฝ”๋“œ :[statics]-[๋ฆฌํ„ฐ๋Ÿด]-[ํ…์ŠคํŠธ]]๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋‹ค.
  • ์ด๋ฒˆ malloc-lab์—์„œ๋Š” ๋™์  ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์™€ malloc,free,new,gc(garbage collector)์˜ ๊ฐœ๋…์„ ํ™œ์šฉํ•˜์—ฌ ๋Ÿฐํƒ€์ž„ ์‹œ์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž.

2. Allocator

1)๋ธ”๋ก ๋‹จ์œ„ ์™œ ์‚ฌ์šฉํ• ๊นŒ?

  • ํŽ˜์ด์ง€ object ํ•˜๋‚˜ํ•˜๋‚˜๋ฅผ ํ• ๋‹นํ•˜๊ธฐ์—๋Š” ๋„ˆ๋ฌด ํผ์งํ•จ.
    • object๊ฐ€ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋Š” ๊ณต๊ฐ„์ด ์—†๊ฑฐ๋‚˜ ํ• ๋‹น ๊ณต๊ฐ„์ด ๋„ˆ๋ฌด ๋‚จ์•„๋Œ์•„์„œ ๋‹ค์Œ object ํ• ๋‹น์— ๋น„ํšจ์œจ์ ์ž„.
  • ๋Œ€์‹  ์ข€ ๋” ์œ ์—ฐํ•˜๊ฒŒ ์ด๋Ÿฐ ์ƒํ™ฉ๋“ค์„ ๋Œ€์ฒ˜ํ•  ์ˆ˜ ์žˆ๋Š” word-aligned๋ธ”๋ก์„ ํ™œ์šฉํ•œ๋‹ค.
  • ์œ„์˜ ํ• ๋‹น๋œ๋ธ”๋ก๋“ค (โฌ›์–ด๋‘์šด ๋ธ”๋ก) & free๋ธ”๋ก(โฌœํฐ๋ธ”๋ก)๋“ค์€ ๊ฐ๊ฐ malloc๊ณผ free๋ฅผ ํ†ตํ•ด์„œ ์ง€์ • ๊ฐ€๋Šฅ

2) Dynamic Memory Allocation

(1) ๋™์  ๋ฉ”๋ชจ๋ฆฌ allocator๋Š” ํ•„์š”ํ•  ๋•Œ๋งŒ memory๋ธ”๋ก์„ ํ• ๋‹นํ•œ๋‹ค

(2) Explicit vs Implicit Memory allocator

2-1 Explicit : aplication allocates + frees space

  • ex. C: malloc & free

2-2 Implicit : apllication allocates only!

3) Explicit Memory Allocator :malloc & free

(1) ๊ธฐ๋ณธ ๊ตฌ์กฐ

  • size : ํ• ๋‹น์„ ํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ์—ฐ์†๋œ ๋ฐ”์ดํŠธ์˜ ํฌ๊ธฐ
  • void* : size๋ฐ”์ดํŠธ ํฌ๊ธฐ ์ด์ƒ์— ํ•ด๋‹น๋˜๋Š” ์ƒˆ๋กœ์ด ํ• ๋‹นํ•œ ๋ธ”๋ก์„ ๊ฐ€๋ฅดํ‚ค๋Š” ํฌ์ธํ„ฐ
  • void* ptr: free๋ฅผ ํ•ด์ฃผ๊ธฐ ์œ„ํ•œ ํฌ์ธํ„ฐ
  • ํ• ๋‹น ์„ฑ๊ณต์‹œ : size๋ฐ”์ดํŠธ๋งŒํผ 8๋ฐ”์ดํŠธ ๋‹จ์œ„๋กœ ์ด์–ด์ง„ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์„ ๊ฐ€๋ฅดํ‚ค๋Š” ํฌ์ธํ„ฐ ๋ฆฌํ„ด
  • ์‹คํŒจ์‹œ : NULL(0)์™€ errno ๋ฆฌํ„ด
  • malloc ์˜ˆ์‹œ

(2) Allocation ์˜ˆ์‹œ (64 ๋น„ํŠธ word)

  • p1์€ 4๋ฐ”์ดํŠธ ํฌ๊ธฐ์˜ wordํ• ๋‹น
  • p2๋Š” 5๋ฐ”์ดํŠธ ํฌ๊ธฐ์˜ wordํ• ๋‹น
  • p3๋Š” 6๋ฐ”์ดํŠธ ํฌ๊ธฐ์˜ wordํ• ๋‹น
  • free(p2)๋Š” p2ํฌ์ธํ„ฐ๊ฐ€ ๊ฐ€๋ฅดํ‚ค๋Š” ๋ธ”๋ก์„ free(๋ฐ˜ํ™˜)
  • p4๋Š” 2๋ฐ”์ดํŠธ ํฌ๊ธฐ์˜ word ํ• ๋‹น

(3) Allocator ์‚ฌ์šฉ์‹œ ๊ณ ๋ คํ•  ์ ๋“ค

1. ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ํ• ๋‹น/free ๊ณต๊ฐ„์„ ์ง€์ •ํ•˜์ง€๋Š” ์•Š์Œ!

  • ๋Œ€์‹  ํ• ๋‹น/freeํ•ด์•ผํ•˜๋Š” ๊ณต๊ฐ„์˜ ํฌ๊ธฐ, ์–ธ์ œ ํ• ๋‹นํ•ด์•ผํ•˜๊ฑฐ๋‚˜ freeํ•ด์•ผํ•˜๋Š” ์ง€์— ๋Œ€ํ•œ ์‹œ์ ์„ ์ง€์ •ํ•œ๋‹ค.

2. ๋น ๋ฅธ ํ• ๋‹น

  • ์ดˆ(sec) ๋‹น malloc ๋˜๋Š” ์ดˆ(sec)๋‹น ๋ง๋กํ•œ ๋ฐ”์ดํŠธ์„ ์ตœ์†Œํ™”ํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•˜์ž!
  • ์ด์ƒ์ ์œผ๋กœ๋Š” ์ƒ์ˆ˜์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋„๋ก, O(n)์ด ๋˜์ง€ ์•Š๋„๋ก!

3. Memory utilization ์ตœ๋Œ€ํ™”

  • ์œ„์ฒ˜๋Ÿผ ์ด์ƒ์ ์œผ๋กœ ํž™์˜์—ญ์— ๋นˆ ๊ณต๊ฐ„์—†์ด ์‚ฌ์šฉ๋  ๊ฑฐ ๊ฐ™์ง€๋งŒ..
  • ํž™์˜์—ญ ๋Œ€๋ถ€๋ถ„์—๋Š” ๋ถˆํ•„์š”ํ•œ ํ”„๋กœ๊ทธ๋žจ ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ๋˜์–ด ์žˆ๋‹ค. ์ตœ๋Œ€ํ•œ ๊ณต๊ฐ„์„ ๋‚ญ๋น„ํ•˜์ง€ ์•Š๋„๋ก ํ•˜์ž.
  • ๐Ÿ‘ฟ fragmentation (์‚ฌ์šฉ๋˜๊ณ  ์žˆ์ง€ ์•Š์Œ์—๋„ ํ• ๋‹นํ•  ์ˆ˜ ์—†๋Š” ๊ณต๊ฐ„)์„ ๋งŒ๋“ค์ง€ ๋ง์ž!

    ๐Ÿค” ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด thoughput (unit ๋‹น ์™„๋ฃŒํ•œ request ๊ฐœ์ˆ˜)์™€ memory utilization๊ฐ„ ์กฐ์œจํ•  ๊ฒƒ์ธ๊ฐ€?

3. fragmentation

1) ์ข…๋ฅ˜

internal fragmentationexternal fragmentation
payload<blockfree๊ณต๊ฐ„ ํ•˜๋‚˜ํ•˜๋‚˜ < word๊ฐ€ ํ• ๋‹น๋ ๋งŒํ•œ ์—ฐ์†๋œ ๊ณต๊ฐ„<=free๊ณต๊ฐ„๋“ค์˜ ์ดํ•ฉ
metadata, alignment, policy์— ๋”ฐ๋ผ ๋ฐœ์ƒ ๊ฐ€๋Šฅํ• ๋‹น๋˜๋Š” free request ์–‘์ƒ์— ๋”ฐ๋ผ์„œ ๋ฐœ์ƒ ๊ฐ€๋Šฅ
โ˜‘๏ธ ํž™ ๋ฐ์ดํ„ฐ๊ตฌ์กฐ ์œ ์ง€ํ•  ๋•Œ ์˜ค๋ฒ„ํ—ค๋“œ ์‹œ ๋ฐœ์ƒ๊ฐ€๋Šฅ
โ˜‘๏ธ alignment ์ค‘ padding์— ์˜ํ•ด ๋ฐœ์ƒ๊ฐ€๋Šฅ
โ˜‘๏ธ policy : ๋ธ”๋ก splitํ•˜์ง€ ์•Š๊ฒ ๋‹ค๊ณ  ๊ฒฐ์ • ์‹œ ๋“ฑ ๋“ฑ
๐Ÿ“Œ placement policy: first-fit, next-fit, best-fit (seglist๊ฐ€ best-fit์‚ฌ์šฉ ์‹œ ์‹œ๊ฐ„ ์ ˆ์•ฝ ์ œ์ผ ๋งŽ์ด ํ•จ!)
๐Ÿ“Œ splitting policy: ํ•ญ์ƒํ•ด์ค„๊นŒ? ๊ฐ€๋”ํ•ด์ค„๊นŒ? ์‚ฌ์ด์ฆˆ์— ๋”ฐ๋ผ ํ•ด์ค„๊นŒ?
๐Ÿ“Œ coalescing policy: immediate vs deferred (๋‹น์žฅ?๋‚˜์ค‘์—?)
๐Ÿ˜Š ์˜ค๋กœ์ง€ ์ด์ „์˜ request ํŒจํ„ด์— ์˜ํ•ด์„œ ๋ฐœ์ƒ ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ ์˜ˆ์ธก & ํ•ด๊ฒฐ์ด ๋น„๊ต์  ์‰ฌ์›€๐Ÿ˜ซ ๋ฏธ๋ž˜ request์— ์˜ํ•ด ๋ฐœ์ƒํ•˜๋ฏ€๋กœ ์˜ˆ์ธก & ํ•ด๊ฒฐ์ด ์–ด๋ ค์›€

2. Internal vs External fragmentation ํ•œ๋ˆˆ์— ๋น„๊ตํ•˜๊ธฐ

  • p1์—์„œ 4๋ฐ”์ดํŠธ word ํ• ๋‹น
  • p2์—์„œ 5๋ฐ”์ดํŠธ word ํ• ๋‹น
  • p3์—์„œ 6๋ฐ”์ดํŠธ word ํ• ๋‹น
  • p2๋ฅผ freeํ•ด์คŒ
  • p4๋Š” 6๋ฐ”์ดํŠธ. ํ• ๋‹น๋˜์ง€ ์•Š์€ ๊ณต๊ฐ„์˜ ํ•ฉ์€ 7๋กœ ์ถฉ๋ถ„ํ•˜์ง€๋งŒ ์—ฐ์†๋œ ๊ณต๊ฐ„์€ ๋ถ€์กฑํ•จ! โžก๏ธ External fragmentation

4. ๊ตฌํ˜„ ์‹œ ๊ณ ๋ คํ•  ํฌ์ธํŠธ๋“ค

๐ŸŽฏtask 1. ํฌ์ธํ„ฐ๋งŒ(free(p)) ์ฃผ์–ด์กŒ์„ ๋•Œ ์–ผ๋งˆ๋งŒํผ free๋ฅผ ํ•ด์ค˜์•ผํ•˜๋Š” ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•?

๐ŸŽฏtask 2. free block์„ tracking ๋ฐฉ๋ฒ•์—๋Š” ๋ญ๊ฐ€ ์žˆ์„๊นŒ?

๐ŸŽฏtask 3. ํ• ๋‹นํ•  ๋ธ”๋ก์„ ๊ณจ๋ผ์ค„ ๋•Œ ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ์ œ์ผ ํšจ์œจ์ ์ผ๊นŒ? (ft. placement)

๐ŸŽฏtask 4. ํ• ๋‹น๋œ free block๋ณด๋‹ค ํฌ๊ธฐ๊ฐ€ ์ž‘์€ ๊ตฌ์กฐ์ฒด (structure)์—์„œ ์—ฌ๋ถ„๊ณต๊ฐ„(extra space)์„ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•ด์•ผํ• ๊นŒ? (ft.splitting)

๐ŸŽฏtask 5. ๋ธ”๋ก์„ free์‹œ์ผœ์ฃผ๋ฉด ๋‚˜์ค‘์— ์‚ฌ์šฉ๊ฐ€๋Šฅํ•˜๋„๋ก ๋งŒ๋“ค์–ด์ค˜์•ผํ•˜๋Š”๋ฐ reinsert ์—ฌ๋ถ€ ๊ฒฐ์ •(ft. merge)

5. ๊ตฌํ˜„ ํฌ์ธํŠธ solutions

[task 1] ์–ผ๋งˆ๋งŒํผ์„ freeํ•ด์ค˜์•ผํ•  ์ง€ ์–ด๋–ป๊ฒŒ ์•Œ๊นŒ?

๐Ÿ’ก Solution: [Standard] data payload ์•ž์˜ header word ๋ธ”๋ก์— ๊ธธ์ด ์ €์žฅ

  • p0์—์„œ 4๋ฐ”์ดํŠธ word๋ฅผ ํ• ๋‹นํ•ด์ค„ ๋•Œ
  • ๋ธ”๋ก์˜ ํฌ๊ธฐ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” metadata๋ฅผ ํ—ค๋”(Header)์— ์ถ”๊ฐ€ํ•ด์ฃผ๊ธฐ (๋Œ€์‹  ์ถ”๊ฐ€์ ์ธ ํ• ๋‹น๊ณต๊ฐ„ ํ•„์š”ํ•จ!)

[task 2] Free block์„ ์–ด๋–ป๊ฒŒ trackํ• ๊นŒ?

๐Ÿ’ก Solution: ๋Œ€ํ‘œ์ ์ธ ๋ฐฉ๋ฒ•์€ implicit list, explicit list, seglist ํ™œ์šฉ ๋“ฑ์ด ์žˆ๋‹ค.

๐Ÿ‘ฉโ€ ๐Ÿ’ปmalloc-lab์—์„œ ์œ„์˜ ์„ธ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ free block์„ ์ถ”์ ํ•˜๋Š” ๋ฐฉ๋ฒ•๋“ค์„ ๊ตฌํ˜„ํ•ด๋ณผ ๊ฒƒ์ด๋‹ค. cf. ํฌ๊ธฐ๋ณ„๋กœ ๋ธ”๋ก sortํ•˜๊ธฐ (RBtree์™€ ๊ฐ™์€ ๊ท ํ˜•ํŠธ๋ฆฌ๋ฅผ ์‚ฌ์šฉ+ free๋ธ”๋ก ๊ฐ๊ฐ์— ํฌ์ธํ„ฐ + ๊ธธ์ด๋ฅผ key๋กœ)

๐Ÿ’ก Splitting, boundary tags, coalescing์€ ๋ชจ๋“  allocator์—์„œ ๊ณตํ†ต์ด๋‹ค.

Implicit Free List

1. Implicit Free List : Block format์œผ๋กœ track

  • ๋ชจ๋“  ๋ธ”๋ก ์—ฐ๊ฒฐ
  • 1 wordํฌ๊ธฐ์˜ ๋ธ”๋ก์—์„œ
    • ๋ธ”๋ก์˜ metadata
      • ๋ธ”๋ก์˜ ํฌ๊ธฐ์— ๋Œ€ํ•œ ์ •๋ณด
      • ํ• ๋‹น ์ƒํƒœ (๐Ÿ…ฐ๏ธ) : Least Significant Bit (LSB) ๊ฐ€ 1์ผ๋•Œ๋Š” ํ• ๋‹น๋จ, 0์ผ ๋•Œ๋Š” free์ธ ์ƒํƒœ
      • ๋ธ”๋ก์˜ ํฌ๊ธฐ๊ฐ€ ํ•ญ์ƒ 2์˜ ์ œ๊ณฑ์ด๋ผ๋ฉด ๊ฐ™์€ word์— ๋น„ํŠธ๋ฅผ ๋„ฃ์„ ์ˆ˜ ์žˆ์Œ (size ์ฝ์„ ๋•Œ lower order bit ์ˆจ๊ธธ ์ˆ˜ ์žˆ์Œ)

2. Implicit Free List : Heap format ์œผ๋กœ track

  • ํž™์˜ ์‹œ์ž‘์— word์‹œ์ž‘์ด ๋ธ”๋ก์˜ ์ผ๋ถ€๊ฐ€ ๋  ์ˆ˜ ์—†์Œ.
  • 16๋ฐ”์ดํŠธ(2word)์˜ ์ œ๊ณฑ์œผ๋กœ ๋ธ”๋ก size๊ฐ€ ์ •ํ•ด์ง€๊ณ , payload๋Š” 16๋ฐ”์ดํŠธ ๋‹จ์œ„๋กœ ๋“ค์–ด๊ฐ„๋‹ค.
  • ๋”ฐ๋ผ์„œ internal fragmentation ๋ฐœ์ƒ๊ฐ€๋Šฅ
  • ๋ธ”๋ก Header์— ๋ธ”๋ก ์‚ฌ์ด์ฆˆ์™€ ๋ธ”๋ก ํ• ๋‹น ์—ฌ๋ถ€๊ฐ€ ๋“ค์–ด์žˆ๋‹ค (metadata)
  • ํž™์˜ ๋์—๋Š” size๊ฐ€ 0์ธ header๊ฐ™์•„๋ณด์ด๋Š” ๋ธ”๋ก์ด ํ• ๋‹น

[task 3] ํ• ๋‹นํ•  ๋ธ”๋ก์„ ๊ณจ๋ผ์ค„ ๋•Œ ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ์ œ์ผ ํšจ์œจ์ ์ผ๊นŒ? (ft. placement)

๐Ÿ’ก Solution: Implicit Free List : Free ๋ธ”๋ก ์ฐพ๋Š” ๋ฒ•

  • First fit : ๋ฆฌ์ŠคํŠธ๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ์ˆœํšŒํ•˜๋ฉด์„œ size๊ฐ€ ๋งž๋Š” ์ฒซ๋ฒˆ์งธ free๋ธ”๋ก ์„ ํƒ
  • Next fit : ์ด์ „ ์ˆœํšŒ๋ฅผ ๋งˆ์ณค๋˜ ๊ณณ์—์„œ first-fit ์ˆ˜ํ–‰
  • Best fit : ๋ฆฌ์ŠคํŠธ ์ „์ฒด๋ฅผ ์ˆœํšŒํ•˜๋ฉด์„œ size-free๋ธ”๋ก ๊ฐ„์˜ ๋ฐ”์ดํŠธ๊ฐ€ ๊ฐ€์žฅ ์ ๊ฒŒ ๋‚จ๋Š” ๊ณณ์„ ์„ ํƒ

[task 4] ํ• ๋‹น๋œ free block๋ณด๋‹ค ํฌ๊ธฐ๊ฐ€ ์ž‘์€ ๊ตฌ์กฐ์ฒด (structure)์—์„œ ์—ฌ๋ถ„๊ณต๊ฐ„(extra space)์„ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•ด์•ผํ• ๊นŒ? (ft.splitting)

๐Ÿ’ก Solution: Implicit Free List : Free ๋ธ”๋ก ํ• ๋‹นํ•˜๋Š” ๋ฒ• (ft.๋ธ”๋ก split)

  • ํ• ๋‹น ์ƒํƒœ : ํ• ๋‹น๋œ๋ธ”๋ก๋“ค (โฌ›์–ด๋‘์šด ๋ธ”๋ก) & free๋ธ”๋ก(โฌœํฐ๋ธ”๋ก)& ๐ŸŸจํฌ์ธํ„ฐ p๊ฐ€ ๊ฐ€๋ฅดํ‚ค๋Š” ๋ธ”๋ก(ํ• ๋‹นํ•˜๋ ค๋Š” ๋ธ”๋ก)
  • 48๋น„ํŠธ(6๋ฐ”์ดํŠธ)์˜ ํ• ๋‹น๋˜์ง€ ์•Š์€ ๊ณต๊ฐ„์ด ์žˆ์„ ๋•Œ
  • p์—์„œ 24๋น„ํŠธ(3๋ฐ”์ดํŠธ)+1๋ฐ”์ดํŠธ(metadataํฌํ•จ) ํฌ๊ธฐ์˜ ๊ณต๊ฐ„์„ ํ• ๋‹นํ•˜๊ณ  ์‹ถ๋‹ค๊ณ  ํ•˜์ž.
  • ํ• ๋‹น๋œ ๊ณต๊ฐ„ <= free ๊ณต๊ฐ„์ผ ๋•Œ ๊ณต๊ฐ„์„ ๋‹ค ์“ฐ๊ธฐ vs. split๋ฅผ ํ•ด์•ผ ํšจ์œจ์ ์ผ๊นŒ?

[task 5] ํ• ๋‹น๋œ free block๋ณด๋‹ค ํฌ๊ธฐ๊ฐ€ ์ž‘์€ ๊ตฌ์กฐ์ฒด (structure)์—์„œ ์—ฌ๋ถ„๊ณต๊ฐ„(extra space)์„ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•ด์•ผํ• ๊นŒ? (ft.splitting)

๐Ÿ’ก Solution: Implicit Free List : ํ• ๋‹น๋œ ๋ธ”๋ก์„ Freeํ•˜๋Š” ๋ฒ•

  • ํ• ๋‹น ์ƒํƒœ : ํ• ๋‹น๋œ๋ธ”๋ก๋“ค (โฌ›์–ด๋‘์šด ๋ธ”๋ก) & free๋ธ”๋ก(โฌœํฐ๋ธ”๋ก) & ๐ŸŸจํฌ์ธํ„ฐ p๊ฐ€ ๊ฐ€๋ฅดํ‚ค๋Š” ๋ธ”๋ก(freeํ•˜๋ ค๋Š” ๋ธ”๋ก)
  • free(p) : ํฌ์ธํ„ฐ p๊ฐ€ ๊ฐ€๋ฅดํ‚ค๋Š” ์œ„์น˜๋ฅผ freeํ•ด์ฃผ๊ณ 
  • malloc(40) : 40๋น„ํŠธ(5๋ฐ”์ดํŠธ)+(1๋ฐ”์ดํŠธ:metadataํฌํ•จ)ํฌ๊ธฐ๋ฅผ ํ• ๋‹นํ•˜๋ ค๊ณ  ํ•  ๋•Œ External fragmentation ๋ฐœ์ƒ! (๊ณต๊ฐ„์€ ์žˆ๋Š”๋ฐ ํ•˜๋‚˜์˜ ๋ธ”๋ก์ด ์•„๋‹˜!)

[task 6] ๋ธ”๋ก์„ free์‹œ์ผœ์ฃผ๋ฉด ๋‚˜์ค‘์— ์‚ฌ์šฉ๊ฐ€๋Šฅํ•˜๋„๋ก ๋งŒ๋“ค์–ด์ค˜์•ผํ•˜๋Š”๋ฐ reinsert

๐Ÿ’ก Solution: Implicit Free List : Freeํ–ˆ๋˜ ๋ธ”๋ก๋“ค ํ•ฉ์ณ์ฃผ๋Š”(Coalescing) ๋ฒ•

  • free(p) : p ํฌ์ธํ„ฐ๊ฐ€ ๊ฐ€๋ฅดํ‚ค๋Š” ์œ„์น˜์˜ ๋ธ”๋ก์„ freeํ–ˆ์„ ๋•Œ, ๋‹ค์Œ free๋ธ”๋ก๋“ค๊ณผ coalesce(ํ•ฉ)ํ•ด์ฃผ๊ธฐ!
    ๐Ÿค” External fragmentation ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๊ฒ ๋„ค! ๊ทธ๋Ÿผ ์•ž์— ์žˆ๋Š” free๋ธ”๋ก๋„ ํ•ฉ์ณ์ฃผ๋ฉด ๊ณต๊ฐ„ ๋” ์ƒ๊ฒจ์„œ ์ข‹์€ ๊ฑฐ ์•„๋‹˜? ๊ทธ๋ž˜์„œ ๋‹ค์Œ์ด ๋‚˜์˜ด
6-1. ์–‘๋ฐฉํ–ฅ Coalescing (bidirectional):

  • footer์— boundary tag๋ฅผ ํฌํ•จ์‹œํ‚ค๊ธฐ
    • boundary tag : header๋ฅผ ๋ณต์ œํ•ด์„œ free ๋ธ”๋ก์˜ ๋์— ๋ถ™์ด๊ธฐ
    • But, ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด ์—ญ์ˆœํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์ถ”๊ฐ€์ ์ธ ๊ณต๊ฐ„์ด ํ•„์š”ํ•ด์ง
6-2. ์ƒ์ˆ˜์‹œ๊ฐ„์œผ๋กœ Coalescing (constant-time):

๐Ÿ‘€constant time coalescing ํ•œ๋ˆˆ์— ๋ณด๊ธฐ

๐Ÿค—ํ˜„์žฌ free๋œ ๋ธ”๋ก ๊ธฐ์ค€์œผ๋กœ ์•ž๋’ค๋กœ free์ธ ๋ธ”๋ก ์กด์žฌ ์—ฌ๋ถ€์— ๋”ฐ๋ผ coalesce ์ƒํƒœ ๋น„๊ต

7. Implicit Free List : ์š”์•ฝ

๊ตฌํ˜„๋‹จ์ˆœํ•จ
ํ• ๋‹นํ•˜๋Š”๋ฐ ์‹œ๊ฐ„๋ณต์žก๋„O(heap์— ์žˆ๋Š” ๋ธ”๋ก์˜ ์ˆ˜)
freeํ•˜๋Š”๋ฐ ์‹œ๊ฐ„๋ณต์žก๋„O(1)
memory utilizationplacement policy์— ๋”ฐ๋ผใ…“
์‚ฌ์šฉ๋„ํ”ํžˆ ์‚ฌ์šฉ X (ํŠน์ˆ˜ํ•œ application ๋ชฉ์ ๋งŒ)

Explicit Free List

  • free ๋ธ”๋ก๋“ค ๊ฐ„์— ํฌ์ธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ฐ€์žฅ ์ ์ ˆํ•œ free ๋ธ”๋ก ๋น ๋ฅด๊ฒŒ ์ฐพ๊ธฐ
  • ํฌ์ธํ„ฐ๋“ค์„ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ์ดํ„ฐ ๊ณต๊ฐ„ ์‚ฌ์šฉ
  • ์ผ๋ฐ˜์ ์œผ๋กœ ์ด์ค‘์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์œผ๋กœ ๊ตฌํ˜„
  • coalsceํ•˜๊ธฐ ์œ„ํ•œ boundary tag ์—ฌ์ „ํžˆ ํ•„์š”
  • ์—ฐ๊ฒฐ๋œ ์ˆœ์„œ๊ฐ€ ๋ธ”๋ก ์ˆœ์„œ์™€ ๋ธ”๋ก ์ˆœ์„œ์™€ ๋ถˆ์ผ์น˜ ํ•  ์ˆ˜ ์žˆ์Œ!

1. Allocated blocks vs Free block

  • ํ• ๋‹น๋œ ๋ธ”๋ก์˜ ๊ตฌ์กฐ
  • ๋ธ”๋ก์˜ ์‚ฌ์ด์ฆˆ + ํ• ๋‹น์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ผ header์™€ footer
  • payload (application data)
  • ๋ถ€๊ฐ€์  ํŒจ๋”ฉ
  • free ๋ธ”๋ก์˜ ๊ตฌ์กฐ
  • ๋ธ”๋ก์˜ ์‚ฌ์ด์ฆˆ + ํ• ๋‹น์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ผ header์™€ footer
  • ๋‹ค์Œ ์ฃผ์†Œ๋ฅผ ๊ฐ€๋ฅดํ‚ค๋Š” ํฌ์ธํ„ฐ, ์ด์ „ ์ฃผ์†Œ๋ฅผ ๊ฐ€๋ฅดํ‚ค๋Š” ํฌ์ธํ„ฐ โžก๏ธ ๋ชจ๋“  ๋ธ”๋ก์˜ implicit list ๋Œ€์‹  free block์— ๋Œ€ํ•œ explicit list ํ™œ์šฉ
  • ์ฆ‰, implicit list์—์„œ๋Š” implicitly(์•”์‹œ์ ์œผ๋กœ)๋ธ”๋ก์˜ ํฌ๊ธฐ๋ฅผ ๊ฐ–๊ณ  free ๋ธ”๋ก์˜ ์œ„์น˜๋ฅผ ์ถ”์ ํ–ˆ์ง€๋งŒ, explicit free list๋Š” ํ• ๋‹น๋œ ๋ธ”๋ก์€ implicit free list์™€ ๋™์ผํ•œ ๊ตฌ์กฐ์ง€๋งŒ free block์€ ์ „ํ›„๋ฅผ ๊ฐ€๋ฅดํ‚ฌ ํฌ์ธํ„ฐ๋กœ explicitly(๋ช…์‹œ์ ์œผ๋กœ) free ๋ธ”๋ก๋“ค์„ ์ถ”์ ํ•จ!

2. List vs. Memory order

3. Explicit Free List: Free ๋ธ”๋ก ํ• ๋‹นํ•˜๋Š” ๋ฒ•

  • explicit free list์˜ ํ•ต์‹ฌ์€ free์ธ ๋ธ”๋ก๋“ค ๊ฐ„์˜ ์ด์ค‘ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋กœ free์ธ ๋ธ”๋ก์„ trackํ•ด์ฃผ๋Š” ๊ฒƒ!
  • ๋ฆฌ์ŠคํŠธ์—์„œ ํ• ๋‹นํ•˜๊ณ ์žํ•˜๋Š” ์œ„์น˜์˜ ํฌ์ธํ„ฐ๋ฅผ ์•ž๊ณผ ๋’ค๊ฐ€ ๊ฐ€๋ฅดํ‚ค๋„๋ก ํ•ด์ฃผ๋ฉด ๋จ.
  • ํ• ๋‹น๋œ ๋ธ”๋ก(โฌ›์–ด๋‘์šด ๋ธ”๋ก)์„ ์ œ์™ธํ•œ split ์ดํ›„์˜ free๋ธ”๋ก(โฌœํฐ๋ธ”๋ก)์„ ํ–ฅํ•ด predecessor์™€ successor์˜ ํฌ์ธํ„ฐ๊ฐ€ ๊ฐ€๋ฅดํ‚ค๋„๋ก ํ•ด์ฃผ๊ธฐ

4. Explicit Free List: Free ํ• ๋‹น๋œ ๋ธ”๋ก์„ Freeํ•˜๋Š” ๋ฒ•

โž• Insertion Policy : freeํ•ด์ค€ ๋ธ”๋ก์„ free list ์–ด๋””์— ๋„ฃ์–ด์ค˜์•ผํ• ๊นŒ?
PolicyLIFO (last in first out)Address-ordered
์žฅ์ ๋‹จ์ˆœํ•˜๊ณ  ์‹œ๊ฐ„๋ณต์žก๋„๊ฐ€ O(1)address-order๋ณด๋‹ค fragmentation์ด ์ข‹๋‹ค๋Š” ์—ฐ๊ตฌ๊ฒฐ๊ณผ ์žˆ์Œ
๋‹จ์ address-order๋ณด๋‹ค fragmentation์ด ์‹ฌํ•˜๋‹ค๋Š” ์—ฐ๊ตฌ๊ฒฐ๊ณผ ์žˆ์Œfreeํ•ด์ค€ ๋ธ”๋ก ์‚ฝ์ž… ์‹œ ์‹œ๊ฐ„๋ณต์žก๋„ O(n)
4-1. LIFO policy
(1) ํ• ๋‹น๋œ ๋‘ ๋ธ”๋ก ์‚ฌ์ด์ผ ๋•Œ


freeํ•ด์ค€ ๋ธ”๋ก์„ free list์˜ Head์— ์œ„์น˜์‹œํ‚ค๊ธฐ


(2) free๋ธ”๋ก๊ณผ ํ• ๋‹น๋œ ๋ธ”๋ก ์‚ฌ์ด์ผ ๋•Œ

predecessor ๋ธ”๋ก์„ ์ž˜๋ผ๋‚ด๊ธฐ(splice) โžก๏ธ ๋‘ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก ํ•ฉ์ณ(coalsce)์ฃผ๊ธฐ โžก๏ธ ์ƒˆ ๋ธ”๋ก์„ free list์˜ Head์— ์œ„์น˜์‹œํ‚ค๊ธฐ (์–‘์ชฝ ๋‘˜๋‹ค ํ˜น์€ ์–‘์ชฝ ํ•œ์ชฝ์—๋‹ค๊ฐ€ ๋ชจ๋‘ ๊ฐ€๋Šฅ)


(3) ํ• ๋‹น๋œ ๋ธ”๋ก๊ณผ free๋ธ”๋ก ์‚ฌ์ด์ผ ๋•Œ


successor ๋ธ”๋ก์„ ์ž˜๋ผ๋‚ด๊ธฐ(splice) โžก๏ธ ๋‘ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก ํ•ฉ์ณ(coalsce)์ฃผ๊ธฐ โžก๏ธ ์ƒˆ ๋ธ”๋ก์„ free list์˜ Head์— ์œ„์น˜์‹œํ‚ค๊ธฐ


(4) free์ธ ๋‘ ๋ธ”๋ก ์‚ฌ์ด์ผ ๋•Œ


successor ๋ธ”๋ก์™€ predecessor ๋ธ”๋ก ์ž˜๋ผ๋‚ด๊ธฐ(splice) โžก๏ธ ์„ธ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก ํ•ฉ์ณ(coalsce)์ฃผ๊ธฐ โžก๏ธ ์ƒˆ ๋ธ”๋ก์„ free list์˜ Head์— ์œ„์น˜์‹œํ‚ค๊ธฐ

4-2. Address-order policy
5. Explicit Free List : ์š”์•ฝ
๊ตฌํ˜„๋น„๊ต์  ๋‹จ์ˆœํ•จ (๋ฆฌ์ŠคํŠธ spliceํ•ด์ค˜์•ผํ•ด์„œ implicit list๋ณด๋‹ค ์ข€ ๋” ๋ณต์žก)
ํ• ๋‹นํ•˜๋Š”๋ฐ ์‹œ๊ฐ„๋ณต์žก๋„O(free ๋ธ”๋ก์˜ ๊ฐœ์ˆ˜) cf.implicit free๋Š” ๋ชจ๋“  ๋ธ”๋ก
freeํ•˜๋Š”๋ฐ ์‹œ๊ฐ„๋ณต์žก๋„O(1)
memory utilizationplacement policy์— ๋”ฐ๋ผ & larger minimum block size (next/prev) vs. implicit list
์‚ฌ์šฉ๋„ํ”ํžˆ ์‚ฌ์šฉ O (+optimization์„ ๋”ํ•จ)
  • linked list์˜ ์ฃผ ์‚ฌ์šฉ ๋ชฉ์ ์€ segregated free list์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•จ์ž„!
    • ์—ฌ๋Ÿฌ๊ฐœ์˜ ๋‹ค์–‘ํ•œ size ํด๋ž˜์Šค ํ˜น์€ ๋‹ค๋ฅธ object ํƒ€์ž…์„ ๋‹ด๊ธฐ ์œ„ํ•œ linked list๋ฅผ ์‚ฌ์šฉํ•ด์„œ segregated free list ๊ตฌํ˜„

Seglist(Segregated free list) Allocators

  • ๊ฐ size bracket(class)์ด ๊ฐ์ž free list๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Œ
  • Explicit free list ์‚ฌ์šฉ ์‹œ๋ณด๋‹ค ๋น ๋ฅด๊ฒŒ ์ ์ ˆํ•œ ํฌ๊ธฐ์˜ free ๋ธ”๋ก ์ฐพ๋„๋ก (best-fit allocation)
  • ์ž‘์€ size๋Š” ๊ฐ๊ฐ์˜ size class๊ฐ€ ์žˆ๊ณ , ํฐ size๋Š” size class๊ฐ€ 2์˜ ์ œ๊ณฑ ํฌ๊ธฐ๋กœ ์žˆ์Œ

1. Simple Segregated Storage

  • ๊ฐ size class๋ฅผ ์œ„ํ•œ heap & free list (๊ฐ™์€ ๋ฆฌ์ŠคํŠธ์— ์žˆ๋Š” ๊ฐ ๋ธ”๋ก๋“ค์€ ๊ฐ™์€ ์‚ฌ์ด์ฆˆ์ž„)
  • split โŒ
  • size๊ฐ€ n์ธ ๋ธ”๋ก์„ ํ• ๋‹นํ•˜๊ธฐ ์œ„ํ•ด์„œ
  • free list์—์„œ size๊ฐ€ n์ด ๋น„์–ด ์žˆ์ง€ ์•Š๋‹ค๋ฉด โžก๏ธ ๋ฆฌ์ŠคํŠธ์˜ ์ฒซ ๋ธ”๋ก์— ํ• ๋‹น (๋ฆฌ์ŠคํŠธ๋Š” implicit์ผ์ˆ˜๋„ explicit์ผ ์ˆ˜๋„ ์žˆ์Œ)
  • free list๊ฐ€ ๋น„์–ด์žˆ๋‹ค๋ฉด โžก๏ธ ์ƒˆ๋กœ์šด ํŽ˜์ด์ง€ ๊ฐ€์ ธ์˜ค๊ธฐ โžก๏ธ ํŽ˜์ด์ง€ ๋‚ด์˜ ๋ชจ๋“  ๋ธ”๋ก์„ ๋ฐ”ํƒ•์œผ๋กœ ์ƒˆ๋กœ์šด free list์ƒ์„ฑโžก๏ธ list์˜ ์ฒซ ๋ธ”๋ก์— ํ• ๋‹นํ•˜๊ธฐ
  • ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ ์ƒ์ˆ˜์‹œ๊ฐ„์ด๋‹ค.
  • ๋ธ”๋ก freeํ•˜๊ธฐ : free list์— ์ถ”๊ฐ€ํ•˜๊ธฐ
  • ๋‹จ์  : ๋น ๋ฅด์ง€๋งŒ fragmentation ์‹ฌ๊ฐํ•  ์ˆ˜ ์žˆ์Œ

2. Segregated Fits (simpe segregated storage ๊ฐœ์„  ver.)

  • free list ๋ฐฐ์—ด๋“ค๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์Œ. ๊ฐ ๋ฐฐ์—ด๋“ค์€ ํŠน์ • size class์„ ์œ„ํ•œ ๋ฐฐ์—ด๋“ค์ด๋‹ค.
  • *size๊ฐ€ n์ธ ๋ธ”๋ก์„ ํ• ๋‹นํ•˜๊ธฐ ์œ„ํ•ด์„œ
    • ์ ์ ˆํ•œ ๋ธ”๋ก ์‚ฌ์ด์ฆˆ์˜ free list ํƒ์ƒ‰
    • ์ ์ ˆํ•œ ๋ธ”๋ก์„ ๋ฐœ๊ฒฌํ•˜๋ฉด
      • ๋ธ”๋ก split + ์ ์ ˆํ•œ ๋ฆฌ์ŠคํŠธ์— fragment ๋‹ด๊ธฐ(์„ ํƒ ์‚ฌํ•ญ)
      • ๋ธ”๋ก ๋ฐœ๊ฒฌ ์‹คํŒจ ์‹œ : ๋‹ค์Œ์œผ๋กœ ํฐ ์‚ฌ์ด์ฆˆ ํด๋ž˜์Šค์—์„œ ํƒ์ƒ‰
      • ์ ์ ˆํ•œ ํฌ๊ธฐ์˜ ๋ธ”๋ก์„ ์ฐพ์„ ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณต
  • ๋ธ”๋ก freeํ•ด์ฃผ๊ธฐ
    • Coalesce + ์ ์ ˆํ•œ ๋ฆฌ์ŠคํŠธ์— ๋„ฃ๊ธฐ (์„ ํƒ ์‚ฌํ•ญ)
  • ์„ฑ๋Šฅ
    • sequential fits ๋ณด๋‹ค ํƒ์ƒ‰์—์„œ ๋น ๋ฆ„
    • simple segregated storage์—์„œ ๋ฐœ์ƒํ•˜๋Š” fragmentation์„ ์กฐ์ ˆํ•จ (Best fit๊ณผ utilization ์„ฑ๋Šฅ ๋น„์Šท)
    • Coalscing ์‹œ free๋ธ”๋ก ํƒ์ƒ‰ ์‹œ๊ฐ„์ด ์ฆ๊ฐ€ํ•  ์ˆ˜ ์žˆ์Œ (์–ด๋–ค size class๊ฐ€ ์ ์ ˆํ•œ ์ง€ ํƒ์ƒ‰ํ•˜๊ธฐ ๋•Œ๋ฌธ) โžก๏ธ deferred coalescing์„ ํ•˜๋ฉด ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Œ (๋ฐ”๋กœ๋ฐ”๋กœ coalesceํ•˜์ง€ ๋ง๊ณ  ๋‚˜์ค‘์—~)

6. ๊ตฌํ˜„

๊นƒํ—ˆ๋ธŒ์—์„œ ๋ณด๊ธฐ

1. naive

๐Ÿ“Œ์„ฑ๋Šฅ์š”์•ฝ
: Perf index = 44 (util) + 9 (thru) = 54/100

/*
 * mm.c - The fastest, least memory-efficient malloc package.
 * 
 * In this naive approach, a block is allocated by simply incrementing
 * the brk pointer.  A block is pure payload. There are no headers or
 * footers.  Blocks are never coalesced or reused. Realloc is
 * implemented directly using mm_malloc and mm_free.
 *
 * NOTE TO STUDENTS: Replace this header comment with your own header
 * comment that gives a high level description of your solution.
 */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>

#include "mm.h"
#include "memlib.h"

// mdriver ๊ตฌ๋™์„ ์œ„ํ•œ team์ •๋ณด struct ์„ค์ •
team_t team = {
    /* Team name */

    "team 1",
    /* First member's full name */
    "hyemin Pyo",
    /* First member's email address */
    "pyolovely01@gmail.com",

    /* Second member's full name (leave blank if none) */
    "",
    /* Second member's email address (leave blank if none) */
    ""};

/* ================================ Macros ===================================== */
// ๊ฐ์ข… ๋ณ€์ˆ˜,ํ•จ์ˆ˜ ์„ค์ •
#define WSIZE 4 // word and header footer ์‚ฌ์ด์ฆˆ๋ฅผ byte๋กœ.
#define DSIZE 8 // double word size๋ฅผ byte๋กœ
#define CHUNKSIZE (1<<12)

/* ------------------------------ Basic Utility ------------------------------- */

#define MAX(x,y) ((x)>(y)? (x) : (y))

// size๋ฅผ packํ•˜๊ณ  ๊ฐœ๋ณ„ word ์•ˆ์˜ bit๋ฅผ ํ• ๋‹น (size์™€ alloc์„ ๋น„ํŠธ์—ฐ์‚ฐ)
#define PACK(size,alloc) ((size)| (alloc))

/* address p์œ„์น˜์— words๋ฅผ read์™€ write๋ฅผ ํ•œ๋‹ค. */
#define GET(p) (*(unsigned int*)(p))
#define PUT(p,val) (*(unsigned int*)(p)=(val))

// address p์œ„์น˜๋กœ๋ถ€ํ„ฐ size๋ฅผ ์ฝ๊ณ  field๋ฅผ ํ• ๋‹น
#define GET_SIZE(p) (GET(p) & ~0x7)
#define GET_ALLOC(p) (GET(p) & 0x1)

/* given block ptr bp, ๊ทธ๊ฒƒ์˜ header์™€ footer์˜ ์ฃผ์†Œ๋ฅผ ๊ณ„์‚ฐ*/
#define HDRP(bp) ((char*)(bp) - WSIZE)
#define FTRP(bp) ((char*)(bp) + GET_SIZE(HDRP(bp)) - DSIZE)

/* GIVEN block ptr bp, ์ด์ „ ๋ธ”๋ก๊ณผ ๋‹ค์Œ ๋ธ”๋ก์˜ ์ฃผ์†Œ๋ฅผ ๊ณ„์‚ฐ*/
#define NEXT_BLKP(bp) ((char*)(bp) + GET_SIZE(((char*)(bp)-WSIZE)))
#define PREV_BLKP(bp) ((char*)(bp) - GET_SIZE(((char*)(bp) - DSIZE)))

static void *coalesce(void *bp){
    size_t prev_alloc = GET_ALLOC(FTRP(PREV_BLKP(bp)));
    size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp)));
    size_t size =  GET_SIZE(HDRP(bp));

    if (prev_alloc && next_alloc){ // case 1 - ์ด์ „๊ณผ ๋‹ค์Œ ๋ธ”๋ก์ด ๋ชจ๋‘ ํ• ๋‹น ๋˜์–ด์žˆ๋Š” ๊ฒฝ์šฐ, ํ˜„์žฌ ๋ธ”๋ก์˜ ์ƒํƒœ๋Š” ํ• ๋‹น์—์„œ ๊ฐ€์šฉ์œผ๋กœ ๋ณ€๊ฒฝ
        return bp;
    }
    else if (prev_alloc && !next_alloc){ // case2 - ์ด์ „ ๋ธ”๋ก์€ ํ• ๋‹น ์ƒํƒœ, ๋‹ค์Œ ๋ธ”๋ก์€ ๊ฐ€์šฉ์ƒํƒœ. ํ˜„์žฌ ๋ธ”๋ก์€ ๋‹ค์Œ ๋ธ”๋ก๊ณผ ํ†ตํ•ฉ ๋จ.
        size += GET_SIZE(HDRP(NEXT_BLKP(bp))); // ๋‹ค์Œ ๋ธ”๋ก์˜ ํ—ค๋”๋งŒํผ ์‚ฌ์ด์ฆˆ ์ถ”๊ฐ€?
        PUT(HDRP(bp),PACK(size,0)); // ํ—ค๋” ๊ฐฑ์‹ 
        PUT(FTRP(bp), PACK(size,0)); // ํ‘ธํ„ฐ ๊ฐฑ์‹ 
    }
    else if(!prev_alloc && next_alloc){ // case 3 - ์ด์ „ ๋ธ”๋ก์€ ๊ฐ€์šฉ์ƒํƒœ, ๋‹ค์Œ ๋ธ”๋ก์€ ํ• ๋‹น ์ƒํƒœ. ์ด์ „ ๋ธ”๋ก์€ ํ˜„์žฌ ๋ธ”๋ก๊ณผ ํ†ตํ•ฉ. 
        size+= GET_SIZE(HDRP(PREV_BLKP(bp)));
        PUT(FTRP(bp), PACK(size,0)); 
        PUT(HDRP(PREV_BLKP(bp)), PACK(size,0)); // ํ—ค๋”๋ฅผ ์ด์ „ ๋ธ”๋ก์˜ BLKP๋งŒํผ ํ†ตํ•ฉ?
        bp = PREV_BLKP(bp);
    }
    else { // case 4- ์ด์ „ ๋ธ”๋ก๊ณผ ๋‹ค์Œ ๋ธ”๋ก ๋ชจ๋‘ ๊ฐ€์šฉ์ƒํƒœ. ์ด์ „,ํ˜„์žฌ,๋‹ค์Œ 3๊ฐœ์˜ ๋ธ”๋ก ๋ชจ๋‘ ํ•˜๋‚˜์˜ ๊ฐ€์šฉ ๋ธ”๋ก์œผ๋กœ ํ†ตํ•ฉ.
        size+= GET_SIZE(HDRP(PREV_BLKP(bp))) + GET_SIZE(FTRP(NEXT_BLKP(bp))); // ์ด์ „ ๋ธ”๋ก ํ—ค๋”, ๋‹ค์Œ ๋ธ”๋ก ํ‘ธํ„ฐ ๊นŒ์ง€๋กœ ์‚ฌ์ด์ฆˆ ๋Š˜๋ฆฌ๊ธฐ
        PUT(HDRP(PREV_BLKP(bp)), PACK(size,0));
        PUT(FTRP(NEXT_BLKP(bp)), PACK(size,0));
        bp = PREV_BLKP(bp);
    }
    return bp;
}
static void *extend_heap(size_t words){ // ์ƒˆ ๊ฐ€์šฉ ๋ธ”๋ก์œผ๋กœ ํž™ ํ™•์žฅ
    char *bp;
    size_t size;
    /* alignment ์œ ์ง€๋ฅผ ์œ„ํ•ด ์ง์ˆ˜ ๊ฐœ์ˆ˜์˜ words๋ฅผ Allocate */
    size = (words%2) ? (words+1) * WSIZE : words * WSIZE;
    if ( (long)(bp = mem_sbrk(size)) == -1){
        return NULL;
    }

    /* free block ํ—ค๋”์™€ ํ‘ธํ„ฐ๋ฅผ initํ•˜๊ณ  epilogue ํ—ค๋”๋ฅผ init*/
    PUT(HDRP(bp), PACK(size,0)); // free block header
    PUT(FTRP(bp),PACK(size,0)); // free block footer
    PUT(HDRP(NEXT_BLKP(bp)), PACK(0,1)); // new epilogue header ์ถ”๊ฐ€

    /* ๋งŒ์•ฝ prev block์ด free์˜€๋‹ค๋ฉด, coalesceํ•ด๋ผ.*/
    return coalesce(bp);
}

static char *heap_listp;
/* 
 * mm_init - initialize the malloc package.
 */
int mm_init(void)
{
 /* create ์ดˆ๊ธฐ ๋นˆ heap*/
    if ((heap_listp = mem_sbrk(4*WSIZE)) == (void*)-1){
        return -1;
    }
    PUT(heap_listp,0);
    PUT(heap_listp + (1*WSIZE), PACK(DSIZE,1));
    PUT(heap_listp + (2*WSIZE), PACK(DSIZE,1));
    PUT(heap_listp + (3*WSIZE), PACK(0,1));
    heap_listp+= (2*WSIZE);

    if (extend_heap(CHUNKSIZE/WSIZE)==NULL)
        return -1;
    return 0;
}


// ๋ธ”๋ก์„ ๋ฐ˜ํ™˜ํ•˜๊ณ  ๊ฒฝ๊ณ„ ํƒœ๊ทธ ์—ฐ๊ฒฐ ์‚ฌ์šฉ -> ์ƒ์ˆ˜ ์‹œ๊ฐ„ ์•ˆ์— ์ธ์ ‘ํ•œ ๊ฐ€์šฉ ๋ธ”๋ก๋“ค๊ณผ ํ†ตํ•ฉํ•˜๋Š” ํ•จ์ˆ˜๋“ค
void mm_free(void *bp){ 
    size_t size = GET_SIZE(HDRP(bp));
    PUT(HDRP(bp),PACK(size,0)); // header, footer ๋“ค์„ free ์‹œํ‚จ๋‹ค.
    PUT(FTRP(bp), PACK(size,0));
    coalesce(bp);
}


static void *find_fit(size_t asize){ // first fit ๊ฒ€์ƒ‰์„ ์ˆ˜ํ–‰
    void *bp;
    for (bp= heap_listp; GET_SIZE(HDRP(bp)) > 0; bp = NEXT_BLKP(bp)){
        if (!GET_ALLOC(HDRP(bp)) && (asize<=GET_SIZE(HDRP(bp)))){
            return bp;
        }
    }
    return NULL; 
}

static void place(void *bp, size_t asize){ // ์š”์ฒญํ•œ ๋ธ”๋ก์„ ๊ฐ€์šฉ ๋ธ”๋ก์˜ ์‹œ์ž‘ ๋ถ€๋ถ„์— ๋ฐฐ์น˜, ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์˜ ํฌ๊ธฐ๊ฐ€ ์ตœ์†Œ ๋ธ”๋กํฌ๊ธฐ์™€ ๊ฐ™๊ฑฐ๋‚˜ ํฐ ๊ฒฝ์šฐ์—๋งŒ ๋ถ„ํ• ํ•˜๋Š” ํ•จ์ˆ˜.
    size_t csize = GET_SIZE(HDRP(bp));
    if ( (csize-asize) >= (2*DSIZE)){
        PUT(HDRP(bp), PACK(asize,1));
        PUT(FTRP(bp), PACK(asize,1));
        bp = NEXT_BLKP(bp);
        PUT(HDRP(bp), PACK(csize-asize,0));
        PUT(FTRP(bp), PACK(csize-asize,0));
    }
    else{
        PUT(HDRP(bp), PACK(csize,1));
        PUT(FTRP(bp), PACK(csize,1));
    }
} 
/* * mm_malloc - Allocate a block by incrementing the brk pointer.  *     Always allocate a block whose size is a multiple of the alignment.  */
 void *mm_malloc(size_t size) // ๊ฐ€์šฉ ๋ฆฌ์ŠคํŠธ์—์„œ ๋ธ”๋ก ํ• ๋‹น ํ•˜๊ธฐ
{
    size_t asize; // ๋ธ”๋ก ์‚ฌ์ด์ฆˆ ์กฐ์ •
    size_t extendsize; // heap์— ๋งž๋Š” fit์ด ์—†์œผ๋ฉด ํ™•์žฅํ•˜๊ธฐ ์œ„ํ•œ ์‚ฌ์ด์ฆˆ
    char *bp;

    /* ๊ฑฐ์ง“๋œ ์š”์ฒญ ๋ฌด์‹œ*/
    if (size == 0) return NULL;

    /* overhead, alignment ์š”์ฒญ ํฌํ•จํ•ด์„œ ๋ธ”๋ก ์‚ฌ์ด์ฆˆ ์กฐ์ •*/
    if (size <= DSIZE){
        asize = 2*DSIZE;
    }
    else {
        asize = DSIZE* ( (size + (DSIZE)+ (DSIZE-1)) / DSIZE );

    }
    /* fit์— ๋งž๋Š” free ๋ฆฌ์ŠคํŠธ๋ฅผ ์ฐพ๋Š”๋‹ค.*/
    if ((bp = find_fit(asize)) != NULL){
        place(bp,asize);
        return bp;
    }

    /* fit ๋งž๋Š”๊ฒŒ ์—†๋‹ค. ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋” ๊ฐ€์ ธ์™€ block์„ ์œ„์น˜์‹œํ‚จ๋‹ค.*/
    extendsize = MAX(asize,CHUNKSIZE);
    if ( (bp=extend_heap(extendsize/WSIZE)) == NULL){
        return NULL;
    }
    place(bp,asize);
    return bp;
}

/*
 * mm_free - Freeing a block does nothing.
 */

/*
 * mm_realloc - Implemented simply in terms of mm_malloc and mm_free
 */
void *mm_realloc(void *ptr, size_t size)
{
    void *oldptr = ptr;
    void *newptr;
    size_t copySize;
    
    newptr = mm_malloc(size);
    if (newptr == NULL)
      return NULL;
    copySize = GET_SIZE(HDRP(oldptr));  
    if (size < copySize)
      copySize = size;
    memcpy(newptr, oldptr, copySize);
    mm_free(oldptr);
    return newptr;
}

2. Implicit list

๐Ÿ“Œ์„ฑ๋Šฅ์š”์•ฝ
: Perf index = 46 (util) + 9 (thru) = 55/100

/*
 * mm.c - implicit free list based malloc package 
 * 
 * Block Format: Minimum size is 8 bytes.
 *  - Allocated-Block Format: [Header - Payload]
 *  - Free-Block Format: [Header - (Space) - Footer]
 * Header/Footer: 1-word holds [block size, prev-bit, alloc-bit]
 *  - prev-bit: is previous block allocated.
 *  - alloc-bit: is current block allocated.
 * List Format: implicit free list
 *    [Head-Block[1] | Regular-Blocks(F/A) ...| Tail-Block[1]]
 * Placement Policy: using first-fit algorithm.
 * Split Policy: always split if remainder is greater than 8 bytes
 * Coalescing Policy: bi-direction coalescing after each unallocation
 * 
 * realloc: split if new size is less than the block size by 8 bytes
 *          allocate-copy-free if new size is greater than block size
 */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>

#include "mm.h"
#include "memlib.h"

/* =============================================================================== */

team_t team = {
  /*team*/
  "team 1",
  /* First member's full name */
  "Hyemin Pyo",
  /* First member's email address */
  "pyolovely01@gmail.com",
  /* Second member's full name (leave blank if none) */
  "",
  /* Second member's email address (leave blank if none) */
  ""
};

/* ========================== Function Prototype =============================== */

inline static void* resize_block(void*, size_t);
inline static void* reallocate_block(void*, size_t);
inline static void* extend_heap(size_t);
inline static void* first_fit(size_t);
inline static void* best_fit(size_t);
inline static void* find_fit(size_t);
inline static void place(void*, size_t);
inline static void* coalesce(void*);
inline static void set_prev_bit(void*, size_t);

/* ========================== Compilation Flags =============================== */

// #define DEBUG                 /* uncomment to turn-on heap checker */

#ifdef DEBUG
  static void mm_check(int line);
  #define heap_check(line) (mm_check(line))
#else
  #define heap_check(line)
#endif

/* ================================ Macros ===================================== */

#define WSIZE 4                           /* Word size in bytes */
#define DSIZE 8                           /* Double word size in bytes */
#define CHUNKSIZE (1<<8)                  /* Minimum heap allocation size */
#define MIN_BLOCK_SIZE 8                  /* Minimum block size */
#define ALIGNMENT 8                       /* Payload Alignment */
#define WTYPE u_int32_t                   /* Word type */
#define BYTE char                         /* Byte type */

/* ------------------------------ Basic Utility ------------------------------- */

/* Move the address ptr by offset bytes */
#define MOVE_BYTE(ptr, offset) ((WTYPE *)((BYTE *)(ptr) + (offset)))
/* Move the address ptr by offset words */
#define MOVE_WORD(ptr, offset) ((WTYPE *)(ptr) + (offset))
/* Read a word from address ptr */
#define READ_WORD(ptr) (*(WTYPE *)(ptr))
/* Write a word value to address ptr */
#define WRITE_WORD(ptr, value) (*(WTYPE *)(ptr) = (value))
/* rounds up size (in bytes) to the nearest multiple of ALIGNMENT */
#define ALIGN(size) (((size) + (ALIGNMENT-1)) & ~0x7)
/* Get the maximum of x and y */
#define MAX(x, y) ((x) > (y)? (x) : (y))
/* Get the minimum of x and y */
#define MIN(x, y) ((x) < (y)? (x) : (y))

/* ----------------------- Header/Footer Macros ---------------------------- */

/* Pack the size, prev-allocated and allocation bits into a word */
#define PACK(size, prev, alloc) ((size) | (prev << 1) | (alloc))
/* Read the size from header/footer word at address Hptr */
#define READ_SIZE(Hptr) (READ_WORD(Hptr) & ~0x7)
/* Read the allocation-bit from header/footer word at address Hptr */
#define READ_ALLOC(Hptr) (READ_WORD(Hptr) & 0x1)
/* Read the prev-allocated-bit from header/footer word at address Hptr */
#define READ_PREV_ALLOC(Hptr) ((READ_WORD(Hptr) & 0x2) >> 1)
/* Write the size, prev-allocated and allocation bits to the word at address Hptr */
#define WRITE(Hptr, size, prev, alloc)\
  (WRITE_WORD((Hptr), PACK((size), (prev), (alloc))))

/* Write the size to the word at address Hptr */
#define WRITE_SIZE(Hptr, size)\
  (WRITE((Hptr), (size), READ_PREV_ALLOC(Hptr), READ_ALLOC(Hptr)))

/* Write allocation-bit to the word at address Hptr */
#define WRITE_ALLOC(Hptr, alloc)\
  (WRITE((Hptr), READ_SIZE(Hptr), READ_PREV_ALLOC(Hptr), alloc))

/* Write prev-allocated-bit to the word at address Hptr */
#define WRITE_PREV_ALLOC(Hptr, prev)\
  (WRITE((Hptr), READ_SIZE(Hptr), prev, READ_ALLOC(Hptr)))

/* ---------------------------- Payload Macros ------------------------------ */

/* Get the header-word pointer from the payload pointer pp */
#define HEADER(pp) (MOVE_WORD(pp, -1))
/* Get the footer-word pointer from the payload pointer pp */
#define FOOTER(pp) (MOVE_BYTE(pp, (BLOCK_SIZE(pp) - DSIZE)))
/* Get next block payload pointer from pp (current payload pointer) */
#define NEXT_BLOCK(pp) (MOVE_BYTE(pp, BLOCK_SIZE(pp)))
/* Get previous block payload pointer from pp (current payload pointer) */
#define PREV_BLOCK(pp) (MOVE_BYTE(pp, - READ_SIZE(MOVE_WORD(pp, -2))))
/* Read the block size at the payload pp */
#define BLOCK_SIZE(pp) (READ_SIZE(HEADER(pp)))
/* Read the payload size at pp */
#define PAYLOAD_SIZE(pp) (BLOCK_SIZE(pp) - WSIZE)
/* Gets the block allocation status (alloc-bit) */
#define GET_ALLOC(pp) (READ_ALLOC(HEADER(pp)))
/* Gets the previous block allocation status (prev-alloc-bit) */
#define GET_PREV_ALLOC(pp) (READ_PREV_ALLOC(HEADER(pp)))
/* Check if the block at the payload pp is free */
#define IS_FREE(pp) (!(GET_ALLOC(pp)))
/* Check if the previous block of the payload pp is free */
#define IS_PREV_FREE(pp) (!(GET_PREV_ALLOC(pp)))


/* Sets the size, prev-allocated and allocation-bit to header of block at pp */
#define SET_HEADER(pp, size, prev, alloc) ((WRITE(HEADER(pp),(size),(prev),(alloc))))
/* Sets the size to header of block at pp */
#define SET_HEADER_SIZE(pp, size) ((WRITE_SIZE(HEADER(pp),(size))))
/* Sets the allocation-bit to header of block at pp */
#define SET_HEADER_ALLOC(pp, alloc) ((WRITE_ALLOC(HEADER(pp),(alloc))))
/* Sets the prev-allocated-bit to header of block at pp */
#define SET_HEADER_PREV_ALLOC(pp, prev) ((WRITE_PREV_ALLOC(HEADER(pp),(prev))))

/* Sets the size, prev-allocated and allocation-bit to header/footer of block at pp */
#define SET_INFO(pp, size, prev, alloc)\
  ((WRITE(HEADER(pp),(size),(prev),(alloc))), \
   (WRITE(FOOTER(pp),(size),(prev),(alloc))))

/* Sets the size to header/footer of block at pp */
#define SET_SIZE(pp, size) (SET_INFO((pp),(size),GET_PREV_ALLOC(pp),GET_ALLOC(pp)))
/* Sets the allocation-bit to header/footer of block at pp */
#define SET_ALLOC(pp, alloc) (SET_INFO((pp),BLOCK_SIZE(pp),GET_PREV_ALLOC(pp),(alloc)))
/* Sets the prev-allocated-bit to header/footer of block at pp */
#define SET_PREV_ALLOC(pp, prev) (SET_INFO((pp),BLOCK_SIZE(pp),(prev),GET_ALLOC(pp)))

/* ======================= Private Global Variables ============================== */

// private global variable
static WTYPE* heap_listp;     /* pointer to first block payload */

/* =========================== Public Functions ================================== */

/* 
 * Initialize the malloc package.
 * return 0 on success, -1 on error.
 */
int mm_init(void) {
  /* Create the initial empty heap */
  if ((heap_listp = mem_sbrk(DSIZE)) == (WTYPE*)-1) return -1;

  WRITE(heap_listp, 0,0,1);                    /* Head Word */
  WRITE(heap_listp + 1, 0,1,1);                /* Tail Word */

  heap_listp += 2;

  /* Extend the empty heap with a free block of CHUNKSIZE bytes */
  if (extend_heap(CHUNKSIZE) == NULL) return -1;
  heap_check(__LINE__);
  return 0;
}

/* 
 *  Allocate an aligned block of memory of at least size bytes
 *  Return address of allocated block on success, NULL on error.
 */
void* mm_malloc(size_t size) {
  if (size == 0) return NULL;
  void* pp;                             /* Payload Pointer */
  size = ALIGN(size + WSIZE);           /* Add header word */

  /* Search the free list for a fit */
  if ((pp = find_fit(size)) == NULL) {
    /* No fit found, request a block from the memory */
    pp = extend_heap(MAX(size, CHUNKSIZE));
    if (pp == NULL) return NULL;
  }

  place(pp, size);
  heap_check(__LINE__);
  return pp;
}

/*
 * Free the allocated block at ptr, and coalesce it.
 */
void mm_free(void* ptr) {
  SET_ALLOC(ptr, 0);
  set_prev_bit(NEXT_BLOCK(ptr), 0);
  coalesce(ptr);
  heap_check(__LINE__);
}

/*
 * # ptr = NULL : allocate block of the given size.
 * # size = 0 : free the given block, return NULL.
 * # else: resize the allocated block at ptr.
 * 
 * Return address of the reallocated block, NULL on error.
 */
void* mm_realloc(void* ptr, size_t size) {
  if (ptr == NULL){
    return mm_malloc(size);
  }else if (size == 0){
    mm_free(ptr);
    return NULL;
  }else{
    ptr = resize_block(ptr, size);
    heap_check(__LINE__);
    return ptr;
  }
}

/* =========================== Private Functions ================================== */

/*
 * Resize the allocated block at pp to have size bytes
 * Return address of the resized block, NULL on error.
 */
static void* resize_block(void* pp, size_t size) {
  size_t asize = MAX(MIN_BLOCK_SIZE, ALIGN(size + WSIZE));
  size_t bsize = BLOCK_SIZE(pp);
  size_t csize = bsize - asize;

  if (asize > bsize) return reallocate_block(pp, size);

  if (csize >= MIN_BLOCK_SIZE){
    SET_HEADER_SIZE(pp, asize);
    void* free_part = NEXT_BLOCK(pp);
    SET_INFO(free_part, csize, 1, 0);
    set_prev_bit(NEXT_BLOCK(free_part), 0);
    coalesce(free_part);
  }

  return pp;
}

/*
 * Allocate block of the given size, copy content, free old block
 * Return address of the new block, NULL on error.
 */
static void* reallocate_block(void* ptr, size_t size) {
  void *newptr = mm_malloc(size);
  if (newptr == NULL) return NULL;
  size_t copy_size = MIN(PAYLOAD_SIZE(ptr), size);
  memcpy(newptr, ptr, copy_size);
  mm_free(ptr);
  return newptr;
}

/**
 * Add free block with aligned size to the end of the heap.
 * Return address of the added free block, NULL on error.
*/
void* extend_heap(size_t size) {
  WTYPE* pp;
  size = ALIGN(size);
  if ((long)(pp = mem_sbrk(size)) == -1) return NULL;

  size_t prev_bit = GET_PREV_ALLOC(pp);
  SET_INFO(pp, size, prev_bit, 0);            /* Initialize a free block */
  SET_HEADER(NEXT_BLOCK(pp), 0,0,1);          /* New Tail Word */

  if (!prev_bit) return coalesce(pp);   /* coalesce if previous block is free */
  return pp;
}

/* Find the first block greater than or equal to size
 * Return address of the first-fit, NULL if no-fit.
*/
static void* first_fit(size_t size) {
  void* pp;

  for (pp = heap_listp; BLOCK_SIZE(pp) > 0; pp = NEXT_BLOCK(pp)) {
    if (IS_FREE(pp) && (size <= BLOCK_SIZE(pp))) return pp;
  }

  return NULL;
}

/* Find the smallest block greater than or equal to size
 * Return address of the best-fit, NULL if no-fit.
*/
static void* best_fit(size_t size) {
  void* pp;
  void* best = NULL;
  size_t best_size = __SIZE_MAX__;

  for (pp = heap_listp; BLOCK_SIZE(pp) > 0; pp = NEXT_BLOCK(pp)) {
    size_t curr_size = BLOCK_SIZE(pp);
    if (IS_FREE(pp) && (size <= curr_size) && (curr_size < best_size)){
      best = pp;
    }
  }

  return best;
}

/**
 * Find a free block with size greater than or equal to size.
 * Return address of a fit-block, NULL if no fit.
*/
static void* find_fit(size_t size) {
  return first_fit(size);
}

/**
 * Allocate the free block at pp.
 * Split the block if the remainder is greater than MIN_BLOCK_SIZE.
*/
static void place(void *pp, size_t size) {
  size_t bsize = BLOCK_SIZE(pp);

  if (bsize < (size + MIN_BLOCK_SIZE)){
    SET_ALLOC(pp, 1);
    set_prev_bit(NEXT_BLOCK(pp), 1);
  }else{
    SET_HEADER(pp, size, GET_PREV_ALLOC(pp), 1);
    pp = NEXT_BLOCK(pp);
    SET_INFO(pp, bsize-size, 1, 0);
  }
}

/**
 * Coalesce the current block with its free previous and/or next blocks.
 * Return the address of the coalesced free-block.
*/
static void* coalesce(void *pp) {
  size_t prev_alloc = GET_PREV_ALLOC(pp);
  size_t next_alloc = GET_ALLOC(NEXT_BLOCK(pp));
  size_t size = BLOCK_SIZE(pp);
  size_t prev_bit = prev_alloc;

  if (prev_alloc && next_alloc) return pp;
  
  if (!next_alloc) size += BLOCK_SIZE(NEXT_BLOCK(pp));

  if (!prev_alloc) {
    pp = PREV_BLOCK(pp);
    size += BLOCK_SIZE(pp);
    prev_bit = GET_PREV_ALLOC(pp);
  }

  SET_INFO(pp, size, prev_bit, 0);
  return pp;
}
/**
 * Sets the prev-bit in the (free/allocated) block at pp.
*/
static void set_prev_bit(void* pp, size_t prev_bit){
  if (IS_FREE(pp)){
    SET_PREV_ALLOC(pp, prev_bit);
  }else{
    SET_HEADER_PREV_ALLOC(pp, prev_bit);
  }
}

/* ========================== Debugging Functions =============================== */

#ifdef DEBUG
/** 
 * Heap Consistency Checker, checks for:
 * - head and tail words of the heap
 * - block header and footer equality for free blocks
 * - block size >= minimum size
 * - payload alignment
 * - coalescing (no contiguous free blocks)
 * - prev-bit correctness.
 * - total heap size
*/
static void mm_check(int line){
  WTYPE* ptr = mem_heap_lo();
  WTYPE* end_ptr = MOVE_BYTE(ptr, mem_heapsize()) - 1;
  // Check head word (size = 0, prev is free, allocated)
  if (READ_SIZE(ptr) != 0){
    printf("Error at %d: head-word size = %u\n",line, READ_SIZE(ptr));
  }

  if (READ_ALLOC(ptr) != 1){
    printf("Error at %d: head-word is not allocated\n",line);
  }

  if (READ_PREV_ALLOC(ptr)){
    printf("Error at %d: head-word is prev is allocated\n",line);
  }

  // Check tail word (size = 0, allocated)
  if (READ_SIZE(end_ptr) != 0){
    printf("Error at %d: tail-word size = %u\n",line, READ_SIZE(end_ptr));
  }

  if (READ_ALLOC(end_ptr) != 1){
    printf("Error at %d: tail-word is not allocated\n",line);
  }

  size_t heap_size = DSIZE;
  int prev_free = 0;

  // Check regular blocks
  for (ptr = heap_listp; ptr < end_ptr; ptr = NEXT_BLOCK(ptr)){
    // check header and footer equality
    if (IS_FREE(ptr) && (READ_WORD(HEADER(ptr)) != READ_WORD(FOOTER(ptr)))){
      printf("Error at %d: at block %p => header = %u, footer = %u\n",
        line, ptr, READ_WORD(HEADER(ptr)), READ_WORD(FOOTER(ptr)));
    }
    // check that block size >= minimum size
    if (BLOCK_SIZE(ptr) < MIN_BLOCK_SIZE){
      printf("Error at %d: block %p has size < min size, (%u < %u)\n",
        line, ptr, BLOCK_SIZE(ptr), MIN_BLOCK_SIZE);
    }
    // check payload alignment
    if((unsigned) ptr % ALIGNMENT){
      printf("Error at %d: block %p is not aligned to %d\n",
        line, ptr, ALIGNMENT);
    }
    // check coalescing.
    if (prev_free && IS_FREE(ptr)){
      printf("Error at %d: two contiguous free blocks not coalesced\n", line);
    }
    // check prev-allocated bit
    if (prev_free != IS_PREV_FREE(ptr)){
      printf("Error at %d: block %p prev-bit is incorrect\n", line, ptr);
    }

    prev_free = IS_FREE(ptr);
    heap_size += BLOCK_SIZE(ptr);
  }
  // check total heap size
  if (heap_size != mem_heapsize()){
    printf("Error at %d: heap size not accurate, %u should be %u\n",
     line, heap_size, mem_heapsize());
  }
}

#endif

3. Explicit list

๐Ÿ“Œ์„ฑ๋Šฅ์š”์•ฝ
: Perf index = 46 (util) + 40 (thru) = 86/100

/* mm.c
 * 
 * Blocks are aligned to double-word boundaries.  This
 * yields 8-byte aligned blocks on a 32-bit processor, and 16-byte aligned
 * blocks on a 64-bit processor.  However, 16-byte alignment is stricter
 * than necessary; the assignment only requires 8-byte alignment.  The
 * minimum block size taken is 4 words.
 * This allocator uses the size of a pointer, e.g., sizeof(void *), to
 * define the size of a word.  This allocator also uses the standard
 * type uintptr_t to define unsigned integers that are the same size
 * as a pointer, i.e., sizeof(uintptr_t) == sizeof(void *).
 */

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "memlib.h"
#include "mm.h"
/*********************************************************
 * NOTE TO STUDENTS: Before you do anything else, please
 * provide your team information in the following struct.
 ********************************************************/

team_t team = {
  "team 1",
  "Hyemin Pyo",
  "pyolovely01@gmail.com",
  "",
  "",
};

//* Basic constants and macros: */
#define WSIZE      sizeof(void *) /* Word and header/footer size (bytes) */
#define DSIZE      (2 * WSIZE)    /* Doubleword size (bytes) */
#define CHUNKSIZE  (1 << 12)      /* Extend heap by this amount (bytes) */

/*Max value of 2 values*/
#define MAX(x, y) ((x) > (y) ? (x) : (y))

/* Pack a size and allocated bit into a word */
#define PACK(size, alloc)  ((size) | (alloc))

/* Read and write a word at address p. */
#define GET(p)       (*(uintptr_t *)(p))
#define PUT(p, val)  (*(uintptr_t *)(p) = (val))

/* Read the size and allocated fields from address p */
#define GET_SIZE(p)   (GET(p) & ~(DSIZE - 1))
#define GET_ALLOC(p)  (GET(p) & 0x1)


/* Given block ptr bp, compute address of its header and footer */
#define HDRP(bp)  ((void *)(bp) - WSIZE)
#define FTRP(bp)  ((void *)(bp) + GET_SIZE(HDRP(bp)) - DSIZE)

/* Given block ptr bp, compute address of next and previous blocks */
#define NEXT_BLKP(bp)  ((void *)(bp) + GET_SIZE(HDRP(bp)))
#define PREV_BLKP(bp)  ((void *)(bp) - GET_SIZE((void *)(bp) - DSIZE))

/* Given ptr in free list, get next and previous ptr in the list */
/* bp is address of the free block. Since minimum Block size is 16 bytes, 
   we utilize to store the address of previous block pointer and next block pointer.
*/
#define GET_NEXT_PTR(bp)  (*(char **)(bp + WSIZE))
#define GET_PREV_PTR(bp)  (*(char **)(bp))

/* Puts pointers in the next and previous elements of free list */
#define SET_NEXT_PTR(bp, qp) (GET_NEXT_PTR(bp) = qp)
#define SET_PREV_PTR(bp, qp) (GET_PREV_PTR(bp) = qp)

/* Global declarations */
static char *heap_listp = 0; 
static char *free_list_start = 0;

/* Function prototypes for internal helper routines */
static void *coalesce(void *bp);
static void *extend_heap(size_t words);
static void *find_fit(size_t asize);
static void place(void *bp, size_t asize);

/* Function prototypes for maintaining free list*/
static void insert_in_free_list(void *bp); 
static void remove_from_free_list(void *bp); 

/* Function prototypes for heap consistency checker routines: */
static void checkblock(void *bp);
static void checkheap(bool verbose);
static void printblock(void *bp); 

/**
 * Initialize the memory manager.
 * @param - void no parameter passed in
 * @return - int 0 for success or -1 for failure
 */
int mm_init(void) {
  
  /* Create the initial empty heap. */
  if ((heap_listp = mem_sbrk(8*WSIZE)) == NULL) 
    return -1;

  PUT(heap_listp, 0);                            /* Alignment padding */
  PUT(heap_listp + (1 * WSIZE), PACK(DSIZE, 1)); /* Prologue header */ 
  PUT(heap_listp + (2 * WSIZE), PACK(DSIZE, 1)); /* Prologue footer */ 
  PUT(heap_listp + (3 * WSIZE), PACK(0, 1));     /* Epilogue header */
  free_list_start = heap_listp + 2*WSIZE; 

  /* Extend the empty heap with a free block of minimum possible block size */
  if (extend_heap(4) == NULL){ 
    return -1;
  }
  return 0;
}

/* 
 * Requires:
 *   size of memory asked by the programmer.
 *
 * Effects:
 *   Allocate a block with at least "size" bytes of payload, unless "size" is
 *   zero.  Returns the address of this block if the allocation was successful
 *   and NULL otherwise.
 */
void *mm_malloc(size_t size) 
{
  size_t asize;      /* Adjusted block size */
  size_t extendsize; /* Amount to extend heap if no fit */
  void *bp;

  /* Ignore spurious requests. */
  if (size == 0)
    return (NULL);

  /* Adjust block size to include overhead and alignment reqs. */
  if (size <= DSIZE)
    asize = 2 * DSIZE;
  else
    asize = DSIZE * ((size + DSIZE + (DSIZE - 1)) / DSIZE);

  /* Search the free list for a fit. */
  if ((bp = find_fit(asize)) != NULL) {
    place(bp, asize);
    return (bp);
  }

  /* No fit found.  Get more memory and place the block. */
  extendsize = MAX(asize, CHUNKSIZE);
  if ((bp = extend_heap(extendsize / WSIZE)) == NULL)  
    return (NULL);
  place(bp, asize);
  return (bp);
} 

/* 
 * Requires:
 *   "bp" is either the address of an allocated block or NULL.
 *
 * Effects:
 *   Free a block.
 */
void mm_free(void *bp){
  size_t size;
  /* Ignore spurious requests. */
  if (bp == NULL)
    return;
  /* Free and coalesce the block. */
  size = GET_SIZE(HDRP(bp));
  PUT(HDRP(bp), PACK(size, 0));
  PUT(FTRP(bp), PACK(size, 0));
  coalesce(bp);
}

/*
 * Requires:
 *   "ptr" is either the address of an allocated block or NULL.
 *
 * Effects:
 *   Reallocates the block "ptr" to a block with at least "size" bytes of
 *   payload, unless "size" is zero.  
 *   If "size" is zero, frees the block "ptr" and returns NULL.  
 *   If the block "ptr" is already a block with at
 *   least "size" bytes of payload, then "ptr" may optionally be returned.
 *   Further if requested size is greater than the current block size at pointer bp
 *   and we have the next block as empty with sum of current block size and next block (which happens to be empty)
 *   then we dont need call malloc but just combine current block and next block to resize them so as to 
 *   satisfy the requested realloc size. 
 *   If nothing can be done then a new block is allocated (using malloc) and the contents of the old block
 *   "ptr" are copied to that new block.  Returns the address of this new
 *   block if the allocation was successful and NULL otherwise.
 */
void *mm_realloc(void *bp, size_t size){
  if((int)size < 0) 
    return NULL; 
  else if((int)size == 0){ 
    mm_free(bp); 
    return NULL; 
  } 
  else if(size > 0){ 
      size_t oldsize = GET_SIZE(HDRP(bp)); 
      size_t newsize = size + 2 * WSIZE; // 2 words for header and footer
      /*if newsize is less than oldsize then we just return bp */
      if(newsize <= oldsize){ 
          return bp; 
      }
      /*if newsize is greater than oldsize */ 
      else { 
          size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp))); 
          size_t csize;
          /* next block is free and the size of the two blocks is greater than or equal the new size  */ 
          /* then we only need to combine both the blocks  */ 
          if(!next_alloc && ((csize = oldsize + GET_SIZE(  HDRP(NEXT_BLKP(bp))  ))) >= newsize){ 
            remove_from_free_list(NEXT_BLKP(bp)); 
            PUT(HDRP(bp), PACK(csize, 1)); 
            PUT(FTRP(bp), PACK(csize, 1)); 
            return bp; 
          }
          else {  
            void *new_ptr = mm_malloc(newsize);  
            place(new_ptr, newsize);
            memcpy(new_ptr, bp, newsize); 
            mm_free(bp); 
            return new_ptr; 
          } 
      }
  }else 
    return NULL;
} 


/*
 * Requires:
 *   "bp" is the address of a newly freed block.
 *
 * Effects:
 *   Perform boundary tag coalescing. 
 *   Removes and inserts appropiate free block pointers to the explicit free list
 *   Returns the address of the coalesced block.
 */
static void *coalesce(void *bp){

  //if previous block is allocated or its size is zero then PREV_ALLOC will be set.
  size_t NEXT_ALLOC = GET_ALLOC(  HDRP(NEXT_BLKP(bp))  );
  size_t PREV_ALLOC = GET_ALLOC(  FTRP(PREV_BLKP(bp))  ) || PREV_BLKP(bp) == bp;
  size_t size = GET_SIZE(HDRP(bp));
  
  /* Next block is only free */   
  if (PREV_ALLOC && !NEXT_ALLOC) {                  
    size += GET_SIZE( HDRP(NEXT_BLKP(bp))  );
    remove_from_free_list(NEXT_BLKP(bp));
    PUT(HDRP(bp), PACK(size, 0));
    PUT(FTRP(bp), PACK(size, 0));
  }
  /* Prev block is only free */  
  else if (!PREV_ALLOC && NEXT_ALLOC) {               
    size += GET_SIZE( HDRP(PREV_BLKP(bp))  );
    bp = PREV_BLKP(bp);
    remove_from_free_list(bp);
    PUT(HDRP(bp), PACK(size, 0));
    PUT(FTRP(bp), PACK(size, 0));
  }
  /* Both blocks are free */ 
  else if (!PREV_ALLOC && !NEXT_ALLOC) {                
    size += GET_SIZE( HDRP(PREV_BLKP(bp))  ) + GET_SIZE( HDRP(NEXT_BLKP(bp))  );
    remove_from_free_list(PREV_BLKP(bp));
    remove_from_free_list(NEXT_BLKP(bp));
    bp = PREV_BLKP(bp);
    PUT(HDRP(bp), PACK(size, 0));
    PUT(FTRP(bp), PACK(size, 0));
  }/* lastly insert bp into free list and return bp */
  insert_in_free_list(bp);
  return bp;
}

/* 
 * Requires:
 *   None.
 *
 * Effects:
 *   Extend the heap with a free block and return that block's address.
 */

static void *extend_heap(size_t words) {
  char *bp;
  size_t size;

  /* Allocate an even number of words to maintain alignment */
  size = (words % 2) ? (words+1) * WSIZE : words * WSIZE;
  //Since minimum block size given to us is 4 words (ie 16 bytes)
  if (size < 16){
    size = 16;
  }
  /* call for more memory space */
  if ((int)(bp = mem_sbrk(size)) == -1){ 
    return NULL;
  }
  /* Initialize free block header/footer and the epilogue header */
  PUT(HDRP(bp), PACK(size, 0));         /* free block header */
  PUT(FTRP(bp), PACK(size, 0));         /* free block footer */
  PUT(HDRP(NEXT_BLKP(bp)), PACK(0, 1)); /* new epilogue header */
  /* coalesce bp with next and previous blocks */
  return coalesce(bp);
}

/*
 * Requires:
 *   Size of memory to find.
 * Effects:
 *   Finds a fit for a block with "asize" bytes from the free list.
 *   Extends the heap in some special cases.
 *   And Returns that block's address
 *   or NULL if no suitable block was found. 
 */

static void *find_fit(size_t asize){
  void *bp;
  static int last_malloced_size = 0;
  static int repeat_counter = 0;
  if( last_malloced_size == (int)asize){
      if(repeat_counter>30){  
        int extendsize = MAX(asize, 4 * WSIZE);
        bp = extend_heap(extendsize/4);
        return bp;
      }
      else
        repeat_counter++;
  }
  else
    repeat_counter = 0;
  for (bp = free_list_start; GET_ALLOC(HDRP(bp)) == 0; bp = GET_NEXT_PTR(bp) ){
    if (asize <= (size_t)GET_SIZE(HDRP(bp)) ) {
      last_malloced_size = asize;
      return bp;
    }
  }
  return NULL;
}

/* 
 * Requires:
 *   "bp" is the address of a free block that is at least "asize" bytes.
 * Effects:
 *   Place a block of "asize" bytes at the start of the free block "bp" and
 *   split that block if the remainder would be at least the minimum block
 *   size. 
 */
static void place(void *bp, size_t asize){
  size_t csize = GET_SIZE(HDRP(bp));

  if ((csize - asize) >= 4 * WSIZE) {
    PUT(HDRP(bp), PACK(asize, 1));
    PUT(FTRP(bp), PACK(asize, 1));
    remove_from_free_list(bp);
    bp = NEXT_BLKP(bp);
    PUT(HDRP(bp), PACK(csize-asize, 0));
    PUT(FTRP(bp), PACK(csize-asize, 0));
    coalesce(bp);
  }
  else {
    PUT(HDRP(bp), PACK(csize, 1));
    PUT(FTRP(bp), PACK(csize, 1));
    remove_from_free_list(bp);
  }
}

/*Inserts the free block pointer int the free_list*/
static void insert_in_free_list(void *bp){
  SET_NEXT_PTR(bp, free_list_start); 
  SET_PREV_PTR(free_list_start, bp); 
  SET_PREV_PTR(bp, NULL); 
  free_list_start = bp; 
}
/*Removes the free block pointer int the free_list*/
static void remove_from_free_list(void *bp){
  if (GET_PREV_PTR(bp))
    SET_NEXT_PTR(GET_PREV_PTR(bp), GET_NEXT_PTR(bp));
  else
    free_list_start = GET_NEXT_PTR(bp);
  SET_PREV_PTR(GET_NEXT_PTR(bp), GET_PREV_PTR(bp));
}


/* 
 * The remaining routines are heap consistency checker routines. 
 */

/*
 * Requires:
 *   "bp" is the address of a block.
 *
 * Effects:
 *   Perform a minimal check on the block "bp".
 */
static void
checkblock(void *bp) 
{

  if ((uintptr_t)bp % DSIZE)
    printf("Error: %p is not doubleword aligned\n", bp);
  if (GET(HDRP(bp)) != GET(FTRP(bp)))
    printf("Error: header does not match footer\n");
}

/* 
 * Requires:
 *   None.
 *
 * Effects:
 *   Perform a minimal check of the heap for consistency. 
 */
void
checkheap(bool verbose) 
{
  void *bp;

  if (verbose)
    printf("Heap (%p):\n", heap_listp);

  if (GET_SIZE(HDRP(heap_listp)) != DSIZE ||
      !GET_ALLOC(HDRP(heap_listp)))
    printf("Bad prologue header\n");
  checkblock(heap_listp);

  for (bp = heap_listp; GET_SIZE(HDRP(bp)) > 0; bp = (void *)NEXT_BLKP(bp)) {
    if (verbose)
      printblock(bp);
    checkblock(bp);
  }

  if (verbose)
    printblock(bp);
  if (GET_SIZE(HDRP(bp)) != 0 || !GET_ALLOC(HDRP(bp)))
    printf("Bad epilogue header\n");
}

/*
 * Requires:
 *   "bp" is the address of a block.
 *
 * Effects:
 *   Print the block "bp".
 */
static void
printblock(void *bp) 
{
  bool halloc, falloc;
  size_t hsize, fsize;

  checkheap(false);
  hsize = GET_SIZE(HDRP(bp));
  halloc = GET_ALLOC(HDRP(bp));  
  fsize = GET_SIZE(FTRP(bp));
  falloc = GET_ALLOC(FTRP(bp));  

  if (hsize == 0) {
    printf("%p: end of heap\n", bp);
    return;
  }

  printf("%p: header: [%zu:%c] footer: [%zu:%c]\n", bp, 
      hsize, (halloc ? 'a' : 'f'), 
      fsize, (falloc ? 'a' : 'f'));
}


/*
 * The last lines of this file configures the behavior of the "Tab" key in
 * emacs.  Emacs has a rudimentary understanding of C syntax and style.  In
 * particular, depressing the "Tab" key once at the start of a new line will
 * insert as many tabs and/or spaces as are needed for proper indentation.
 */

/* Local Variables: */
/* mode: c */
/* c-default-style: "bsd" */
/* c-basic-offset: 8 */
/* c-continued-statement-offset: 4 */
/* indent-tabs-mode: t */
/* End: */

4. Seglist

๐Ÿ“Œ์„ฑ๋Šฅ์š”์•ฝ
: Perf index = 58 (util) + 40 (thru) = 98/100

/*
 * mm.c
 * 
 * Block Format: Minimum size is 16 bytes.
 *  - Free-Block Format: [Header - Pred - Succ - (Empty) - Footer]
 *  - Allocated-Block Format: [Header - Payload - Footer]
 *  - Header/Footer: 1-word holds size of the block and allocation-bit at LSB(Least Significant Bit)
 *  - Pred: 1-word holds the address of the predecessor free-block.
 *  - Succ: 1-word holds the address of the successor free-block.
 * 
 * List Format: array of 8 explicit-free lists
 * Heap Format: [seglist-array[8] | Head-Block[1] | Regular-Blocks ...| Tail-Block[1]]
 *  - Head/Tail: 1-word allocated block of zero size.
 * 
 * Placement Policy: using best-fit algorithm.
 * Split Policy: split if remainder is greater than 16 bytes
 * Coalescing Policy: bi-direction coalescing for free-blocks and allocated-blocks
 * Heap Extension Policy: 
 *  - if the size is greater than CHUNK_SIZE: extend by one block of the given size
 *  - else: extend the heap by a few blocks each of the given size. 
 * 
 * realloc:
 *  - if new-size is greater than current-size: expand the block if it can be expanded,
 *    otherwise, reallocate the block (allocate - copy - free).
 *  - if the new-size is less than current size by 64 byte at least then split.
 * 
 * NOTE: Coalescing is not strict, there are some free blocks not coalesced just to keep
 *       a variety of sizes in the seglist.
 */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>

#include "mm.h"
#include "memlib.h"

/* =============================================================================== */

team_t team = {
  /* Team name */
  "pyotato",
  /* First member's full name */
  "Hyemin PYo",
  /* First member's email address */
  "pyolovely01@gmail.com",
  /* Second member's full name (leave blank if none) */
  "",
  /* Second member's email address (leave blank if none) */
  ""
};

/* ========================== Function Prototype =============================== */

inline static void* resize_block(void*, size_t);
inline static void* reallocate_block(void*, size_t);
inline static int can_expand(void*, size_t);
inline static void* expand_block(void*, size_t);
inline static void chop_block(void*, size_t);
inline static void* extend_heap(size_t);
inline static void* first_fit(void*, size_t);
inline static void* best_fit(void*, size_t);
inline static void* find_fit(size_t);
inline static void* place(void*, size_t);
inline static void* coalesce(void*);
inline static void link_block(void*);
inline static void unlink_block(void*);
inline static int seg_index(size_t);

/* ========================== Compilation Flags =============================== */

// #define DEBUG                 /* uncomment to turn-on heap checker */

#ifdef DEBUG
  static void mm_check(int);
  static void check_seglist(int, int);
  static int check_free_list(int, int);
  #define heap_check(line) (mm_check(line))
#else
  #define heap_check(line)
#endif
//NOTE at 236: two contiguous free blocks not coalesced ์‹์œผ๋กœ heap ์ฒดํฌ ๊ฐ€๋Šฅ
/* ================================ Macros ===================================== */

#define WSIZE 4                           /* Word size in bytes */
#define DSIZE 8                           /* Double word size in bytes */
#define CHUNKSIZE (1<<8)                  /* Minimum heap allocation size */
#define MIN_BLOCK_SIZE 16                 /* Minimum block size */
#define ALIGNMENT 8                       /* Payload Alignment */
#define SEGLIST_NUM 8                     /* The Number of lists in the seglist */
#define WTYPE u_int32_t                   /* Word type */
#define BYTE char                         /* Byte type */

/* ------------------------------ Basic Utility ------------------------------- */

/* Move the address ptr by offset bytes */
#define MOVE_BYTE(ptr, offset) ((WTYPE *)((BYTE *)(ptr) + (offset)))
/* Move the address ptr by offset words */
#define MOVE_WORD(ptr, offset) ((WTYPE *)(ptr) + (offset))
/* Read a word from address ptr */
#define READ_WORD(ptr) (*(WTYPE *)(ptr))
/* Write a word value to address ptr */
#define WRITE_WORD(ptr, value) (*(WTYPE *)(ptr) = (value))
/* rounds up size (in bytes) to the nearest multiple of ALIGNMENT */
#define ALIGN(size) (((size) + (ALIGNMENT-1)) & ~0x7)
/* Get the maximum of x and y */
#define MAX(x, y) (((x) > (y))? (x) : (y))
/* Get the minimum of x and y */
#define MIN(x, y) (((x) < (y))? (x) : (y))

/* ----------------------- Header/Footer Macros ---------------------------- */

/* Pack the size and allocated-bit into a word */
#define PACK(size, alloc) ((size) | (alloc))
/* Read the size from header/footer word at address Hptr */
#define READ_SIZE(Hptr) (READ_WORD(Hptr) & ~0x7)
/* Read the allocated-bit from header/footer word at address Hptr */
#define READ_ALLOC(Hptr) (READ_WORD(Hptr) & 0x1)
/* Write the size and allocation-bit to the word at address Hptr */
#define WRITE(Hptr, size, alloc) (WRITE_WORD((Hptr), PACK((size), (alloc))))
/* Write the size to the word at address Hptr */
#define WRITE_SIZE(Hptr, size) (WRITE((Hptr), (size), READ_ALLOC(Hptr)))
/* Write allocation-bit to the word at address Hptr */
#define WRITE_ALLOC(Hptr, alloc) (WRITE((Hptr), READ_SIZE(Hptr), (alloc)))

/* ---------------------------- Payload Macros ------------------------------ */

/* Get the header-word pointer from the payload pointer pp */
#define HEADER(pp) (MOVE_WORD(pp, -1))
/* Get the footer-word pointer from the payload pointer pp */
#define FOOTER(pp) (MOVE_BYTE(pp, PAYLOAD_SIZE(pp)))
/* Get next block payload pointer from pp (current payload pointer) */
#define NEXT_BLOCK(pp) (MOVE_BYTE(pp, BLOCK_SIZE(pp)))
/* Get previous block payload pointer from pp (current payload pointer) */
#define PREV_BLOCK(pp) (MOVE_BYTE(pp, - READ_SIZE(MOVE_WORD(pp, -2))))
/* Read the block size at the payload pp */
#define BLOCK_SIZE(pp) (READ_SIZE(HEADER(pp)))
/* Read the payload size at pp */
#define PAYLOAD_SIZE(pp) (BLOCK_SIZE(pp) - DSIZE)
/* Check if the block at the payload pp is free */
#define IS_FREE(pp) (!(READ_ALLOC(HEADER(pp))))

/* Sets the size and allocation-bit to header/footer of block at pp */
#define SET_INFO(pp, size, alloc)\
  ((WRITE(HEADER(pp),(size),(alloc))), \
   (WRITE(FOOTER(pp),(size),(alloc))))

/* Sets the size to header/footer of block at pp */
#define SET_SIZE(pp, size)\
  ((WRITE_SIZE(HEADER(pp),(size))), \
   (WRITE_SIZE(FOOTER(pp),(size))))

/* Sets the allocation-bit to header/footer of block at pp */
#define SET_ALLOC(pp, alloc)\
  ((WRITE_ALLOC(HEADER(pp),(alloc))), \
   (WRITE_ALLOC(FOOTER(pp),(alloc))))

/* Get the predecessor payload address */
#define GET_PRED(pp) ((WTYPE *)(READ_WORD(pp)))
/* Get the successor payload address */
#define GET_SUCC(pp) ((WTYPE *)(READ_WORD(MOVE_WORD(pp, 1))))
/* Set the predecessor payload address to pred_pp */
#define SET_PRED(pp, pred_pp) (WRITE_WORD(pp, ((WTYPE) pred_pp)))
/* Set the successor payload address to succ_pp */
#define SET_SUCC(pp, succ_pp) (WRITE_WORD(MOVE_WORD(pp, 1), ((WTYPE) succ_pp)))

/* ======================= Private Global Variables ============================== */

// private global variable
static WTYPE** seglist;       /* array of free-list pointers */

/* =========================== Public Functions ================================== */

/* 
 * Initialize the malloc package.
 * return 0 on success, -1 on error.
 */
int mm_init(void) {
  /* Create the initial empty heap */
  void* heap = mem_sbrk((SEGLIST_NUM + 2) * WSIZE); /* seglist + head + tail */
  if (heap == (void*)-1) return -1;

  seglist = heap;
  heap = MOVE_WORD(heap, SEGLIST_NUM);
  // initialize the seglist
  for(int i = 0; i < SEGLIST_NUM; ++i){
    seglist[i] = NULL;
  }

  WRITE(heap, 0, 1);                          /* Head Word */
  WRITE(MOVE_WORD(heap, 1), 0, 1);            /* Tail Word */

  /* Extend the empty heap with a small free block */
  if (extend_heap(4 * MIN_BLOCK_SIZE) == NULL) return -1;
  heap_check(__LINE__);
  return 0;
}

/* 
 *  Allocate an aligned block of memory of at least size bytes
 *  Return address of allocated block on success, NULL on error.
 */
void* mm_malloc(size_t size) {
  if (size == 0) return NULL;
  void* pp;                             /* Payload Pointer */
  size = ALIGN(size + DSIZE);           /* Add header and footer words */
  size = MAX(size, MIN_BLOCK_SIZE);

  /* Search the free list for a fit */
  if ((pp = find_fit(size)) == NULL) {
    /* No fit found, request a block from the memory */
    if (size > CHUNKSIZE){
      pp = extend_heap(size);
    }else{
      pp = extend_heap(4 * CHUNKSIZE);
      chop_block(pp, size);
    }
    if (pp == NULL) return NULL;
  }

  pp = place(pp, size);
  heap_check(__LINE__);
  return pp;
}

/*
 * Free the allocated block at ptr, and coalesce it.
 */
void mm_free(void* ptr) {
  SET_ALLOC(ptr, 0);
  link_block(ptr);
  coalesce(ptr);
  heap_check(__LINE__);
}

/*
 * # ptr = NULL : allocate block of the given size.
 * # size = 0 : free the given block, return NULL.
 * # else: resize the allocated block at ptr.
 * 
 * Return address of the reallocated block, NULL on error.
 */
void* mm_realloc(void* ptr, size_t size) {
  if (ptr == NULL){
    return mm_malloc(size);
  }else if (size == 0){
    mm_free(ptr);
    return NULL;
  }else{
    ptr = resize_block(ptr, size);
    heap_check(__LINE__);
    return ptr;
  }
}

/* =========================== Private Functions ================================== */

/*
 * Resize the allocated block at pp to have size bytes
 * Return address of the resized block, NULL on error.
 */
static void* resize_block(void* pp, size_t size) {
  size_t asize = MAX(MIN_BLOCK_SIZE, ALIGN(size + DSIZE));
  size_t bsize = BLOCK_SIZE(pp);
  size_t csize = bsize - asize;

  if (asize > bsize) {
    if (can_expand(pp, asize)) return expand_block(pp, asize);
    return reallocate_block(pp, size);
  }

  // Split only if the fragment is large enough.
  if (csize >= (4 * MIN_BLOCK_SIZE)){
    SET_INFO(pp, asize, 1);
    void* fp = NEXT_BLOCK(pp);
    SET_INFO(fp, csize, 0);
    link_block(fp);
  }

  return pp;
}

/*
 * Allocate block of the given size, copy content, free old block
 * Return address of the new block, NULL on error.
 */
static void* reallocate_block(void* ptr, size_t size) {
  void *newptr = mm_malloc(size);
  if (newptr == NULL) return NULL;
  size_t copy_size = MIN(PAYLOAD_SIZE(ptr), size);
  memcpy(newptr, ptr, copy_size);
  mm_free(ptr);
  return newptr;
}

/**
 * checks if the allocated-block at pp can expand to have the given size
 */
static int can_expand(void* pp, size_t size){
  size_t bsize = BLOCK_SIZE(pp);

  for(void* ptr = NEXT_BLOCK(pp); IS_FREE(ptr) ; ptr = NEXT_BLOCK(ptr)){
    bsize += BLOCK_SIZE(ptr);
    if (bsize >= size) return 1;
  }

  for(void* ptr = pp; !READ_ALLOC(MOVE_WORD(ptr, -2)) ; ){
    ptr = PREV_BLOCK(ptr);
    bsize += BLOCK_SIZE(ptr);
    if (bsize >= size) return 1;
  }

  return 0;
}

/**
 * expands the allocated-block at pp until it has the given size
 * return address to the new expanded block
*/
static void* expand_block(void *pp, size_t size) {
  void* cpp = pp;
  size_t bsize = BLOCK_SIZE(pp);

  for(void* ptr = NEXT_BLOCK(pp); IS_FREE(ptr) ; ptr = NEXT_BLOCK(ptr)){
    bsize += BLOCK_SIZE(ptr);
    unlink_block(ptr);
    if (bsize >= size) break;
  }

  if (bsize >= size) {
    SET_INFO(cpp, bsize, 1);
    return cpp;
  }

  for(void* ptr = pp; !READ_ALLOC(MOVE_WORD(ptr, -2)) ; ){
    cpp = ptr = PREV_BLOCK(ptr);
    bsize += BLOCK_SIZE(ptr);
    unlink_block(ptr);
    if (bsize >= size) break;
  }
   
  if (cpp != pp) memmove(cpp, pp, PAYLOAD_SIZE(pp));
  SET_INFO(cpp, bsize, 1);
  return cpp;
}

/**
 * chop the given free-block into a small free-blocks of the given size.
*/
static void chop_block(void* pp, size_t size){
  if ((pp == NULL) || (size < MIN_BLOCK_SIZE)) return;
  size_t bsize = BLOCK_SIZE(pp);
  if ((size + MIN_BLOCK_SIZE) > bsize) return;
  unlink_block(pp);

  while(bsize >= (size + MIN_BLOCK_SIZE)){
    SET_INFO(pp, size, 0);
    link_block(pp);
    pp = NEXT_BLOCK(pp);
    bsize -= size;
  }

  SET_INFO(pp, bsize, 0);
  link_block(pp);
}

/**
 * Add free block with aligned size to the end of the heap.
 * Return address of the added free block, NULL on error.
*/
void* extend_heap(size_t size) {
  WTYPE* pp;
  size = ALIGN(size);
  if ((long)(pp = mem_sbrk(size)) == -1) return NULL;

  SET_INFO(pp, size, 0);                      /* Initialize a free block */
  link_block(pp);
  WRITE(HEADER(NEXT_BLOCK(pp)), 0, 1);        /* New Tail Word */

  return pp;
}

/* Find the first block greater than or equal to size
 * Return address of the first-fit, NULL if no-fit.
*/
static void* first_fit(void* free_list, size_t size) {
  for (void* pp = free_list; pp != NULL ; pp = GET_SUCC(pp)) {
    if (size <= BLOCK_SIZE(pp)) return pp;
  }
  return NULL;
}

/* Find the smallest block greater than or equal to size
 * Return address of the best-fit, NULL if no-fit.
*/
static void* best_fit(void* free_list, size_t size) {
  void* pp;
  void* best = NULL;
  size_t best_size = __SIZE_MAX__;

  for (pp = free_list; pp != NULL ; pp = GET_SUCC(pp)) {
    size_t curr_size = BLOCK_SIZE(pp);
    if ((size <= curr_size) && (curr_size < best_size)){
      best = pp;
    }
  }

  return best;
}

/**
 * Find a free block with size greater than or equal to size.
 * Return address of a fit-block, NULL if no fit.
*/
static void* find_fit(size_t size) {
  for(int i = seg_index(size); i < SEGLIST_NUM; ++i){
    void* fit = best_fit(seglist[i], size);
    if (fit != NULL) return fit;
  }
  return NULL;
}

/**
 * Allocate the free block at pp.
 * Split the block if the remainder is greater than MIN_BLOCK_SIZE.
 * Returns the address of the allocated block payload
*/
static void* place(void *pp, size_t size) {
  size_t bsize = BLOCK_SIZE(pp);
  size_t csize = bsize - size;

  unlink_block(pp);
  if (csize < MIN_BLOCK_SIZE){
    SET_ALLOC(pp, 1);
  }else{
    SET_INFO(pp, csize, 0);
    link_block(pp);
    pp = NEXT_BLOCK(pp);
    SET_INFO(pp, size, 1);
  }

  return pp;
}

/**
 * Coalesce the current block with its free previous and/or next blocks.
 * Return the address of the coalesced block.
*/
static void* coalesce(void *pp) {
  void* cpp = pp;                            /* coalesced payload pointer */
  void* prev_footer = MOVE_WORD(pp, -2);
  void* next_header = HEADER(NEXT_BLOCK(pp));
  
  size_t prev_alloc = READ_ALLOC(prev_footer);
  size_t next_alloc = READ_ALLOC(next_header);
  size_t curr_alloc = !IS_FREE(pp);
  size_t size = BLOCK_SIZE(pp);

  if (prev_alloc && next_alloc) return pp;

  if (!curr_alloc) unlink_block(pp);

  if (!next_alloc) {
    size += READ_SIZE(next_header);
    unlink_block(MOVE_WORD(next_header, 1));
  }

  if (!prev_alloc) {
    size += READ_SIZE(prev_footer);
    cpp = PREV_BLOCK(pp);
    unlink_block(cpp);
    if (curr_alloc) memmove(cpp, pp, PAYLOAD_SIZE(pp));
  } 

  SET_INFO(cpp, size, curr_alloc);
  if (!curr_alloc) link_block(cpp);

  return cpp;
}

/**
 * Add the block at pp to the free-list
*/
static void link_block(void* pp){
  int index = seg_index(BLOCK_SIZE(pp));
  WTYPE* list = seglist[index];
  if (list) SET_PRED(list, pp);
  SET_SUCC(pp, list);
  SET_PRED(pp, NULL);
  seglist[index] = pp;
}

/**
 * Remove the block at pp from the free-list 
*/
static void unlink_block(void* pp) {
  int index = seg_index(BLOCK_SIZE(pp));
  WTYPE* pred_pp = GET_PRED(pp);
  WTYPE* succ_pp = GET_SUCC(pp);
  if (pred_pp) SET_SUCC(pred_pp, succ_pp);
  if (succ_pp) SET_PRED(succ_pp, pred_pp);
  if (pp == seglist[index]) seglist[index] = succ_pp;
}

/**
 * Returns the index of the seglist that should contain blocks of the given size 
*/
static int seg_index(size_t size){
  if (size <= MIN_BLOCK_SIZE) return 0;
  if (size <= (2 * MIN_BLOCK_SIZE)) return 1;
  if (size <= (4 * MIN_BLOCK_SIZE)) return 2;
  if (size <= (8 * MIN_BLOCK_SIZE)) return 3;
  if (size <= (16 * MIN_BLOCK_SIZE)) return 4;
  if (size <= (64 * MIN_BLOCK_SIZE)) return 5;
  if (size <= (256 * MIN_BLOCK_SIZE)) return 6;
  return 7;
}

/* ========================== Debugging Functions =============================== */

#ifdef DEBUG
/** 
 * Heap Consistency Checker, checks for:
 * - head and tail words of the heap
 * - block header and footer equality
 * - block size >= minimum size
 * - payload alignment
 * - coalescing (no contiguous free blocks)
 * - total heap size
 * - seglist consistency.
*/
static void mm_check(int line){
  WTYPE* ptr = MOVE_WORD(mem_heap_lo(), SEGLIST_NUM);
  WTYPE* end_ptr = MOVE_BYTE(ptr, mem_heapsize()) - (SEGLIST_NUM + 1); 
  // Check head word (size = 0, allocated)
  if (READ_SIZE(ptr) != 0){
    printf("Error at %d: head-word size = %u\n",line, READ_SIZE(ptr));
  }

  if (READ_ALLOC(ptr) != 1){
    printf("Error at %d: head-word is not allocated\n",line);
  }

  // Check tail word (size = 0, allocated)
  if (READ_SIZE(end_ptr) != 0){
    printf("Error at %d: tail-word size = %u\n",line, READ_SIZE(end_ptr));
  }

  if (READ_ALLOC(end_ptr) != 1){
    printf("Error at %d: tail-word is not allocated\n",line);
  }

  size_t heap_size = (SEGLIST_NUM + 2) * WSIZE;
  int free_count = 0;
  int prev_free = 0;

  // Check regular blocks
  for (ptr = MOVE_WORD(ptr, 2); ptr < end_ptr; ptr = NEXT_BLOCK(ptr)){
    // check header and footer equality
    if (READ_WORD(HEADER(ptr)) != READ_WORD(FOOTER(ptr))){
      printf("Error at %d: at block %p => header = %u, footer = %u\n",
        line, ptr, READ_WORD(HEADER(ptr)), READ_WORD(FOOTER(ptr)));
    }
    // check that block size >= minimum size
    if (BLOCK_SIZE(ptr) < MIN_BLOCK_SIZE){
      printf("Error at %d: block %p has size < min size, (%u < %u)\n",
        line, ptr, BLOCK_SIZE(ptr), MIN_BLOCK_SIZE);
    }
    // check payload alignment
    if((unsigned) ptr % ALIGNMENT){
      printf("Error at %d: block %p is not aligned to %d\n",
        line, ptr, ALIGNMENT);
    }
    // check coalescing.
    if (prev_free && IS_FREE(ptr)){
      printf("NOTE at %d: two contiguous free blocks not coalesced\n", line);
    }

    if(IS_FREE(ptr)) ++free_count;
    prev_free = IS_FREE(ptr);
    heap_size += BLOCK_SIZE(ptr);
  }
  // check total heap size
  if (heap_size != mem_heapsize()){
    printf("Error at %d: heap size not accurate, %u should be %u\n",
     line, heap_size, mem_heapsize());
  }
  // check seglist consistency
  check_seglist(line, free_count);
}

/** 
 * Seglist Consistency Checker, checks for:
 * - seglist pointer
 * - each free-list consistency
 * - the free-block count in seglist matches the free_count (free-blocks in the heap)
*/
static void check_seglist(int line, int free_count){
  int count = 0;
  // checks the seglist pointer
  if (seglist != mem_heap_lo()){
    printf("Error at %d: Seglist pointer doesn't point to heap start address.\n",
      line);
  }
  // check each free-list in the seglist
  for(int i = 0; i < SEGLIST_NUM; ++i){
    count += check_free_list(line, i);
  }
  // check the free-block count in seglist matches the free_count
  if (count != free_count){
    printf("Error at %d: %d missing free-blocks from the seglist.\n",
      line, (free_count - count));
  }
}

/** 
 * Free-List Consistency Checker, checks for:
 * - blocks are free.
 * - free-blocks are in heap range.
 * - the predecessor consistency.
 * Return the number of blocks in the free-list
*/
static int check_free_list(int line, int li){
  void* start_ptr = MOVE_WORD(mem_heap_lo(), SEGLIST_NUM);
  void* end_ptr = MOVE_BYTE(start_ptr, mem_heapsize()) - (SEGLIST_NUM + 1); 
  void* pred_pp = NULL;
  int count = 0;

  for(void* pp = seglist[li]; pp != NULL; pp = GET_SUCC(pp)){
    // check if block is free
    if (!IS_FREE(pp)){
      printf("Error at %d: Seglist[%d] contains an allocated-block %p.\n",
        line, li, pp);
    }
    // check if free-block in heap range
    if (pp <= start_ptr || pp >= end_ptr){
      printf("Error at %d: Seglist[%d] contains a free-block %p out of the heap range.\n",
        line, li, pp);
    }
    // check the predecessor pointer
    if (pred_pp != GET_PRED(pp)){
      printf("Error at %d: in Seglist[%d], inconsistant predecessor link at %p.\n",
        line, li, pp );
    }

    ++count;
    pred_pp = pp;
  }

  return count;
}

#endif

references


๐Ÿค— ์˜คํƒ€, ์ˆ˜์ •ํ•ด์•ผํ•  ๋‚ด์šฉ์€ ๋Œ“๊ธ€๋กœ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ๊ณต๋ถ€ ์ค‘์ธ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜์—ฌ ์˜ฌ๋ฆฐ ๊ฒƒ์ด๋ฏ€๋กœ ํ‹€๋ฆฐ ๋‚ด์šฉ์— ๊ด€ํ•ด์„œ ์ฝ”๋ฉ˜ํŠธ ๋ฐ ์งˆ๋ฌธ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค.

profile
https://pyotato-dev.tistory.com/ ๋กœ ์ด์‚ฌ์ค‘ ๐Ÿšš๐Ÿ’จ๐Ÿš›๐Ÿ’จ๐Ÿšš๐Ÿ’จ

0๊ฐœ์˜ ๋Œ“๊ธ€