c++ 内存管理 3 malloc/free 的简单实现(隐式链表/显式链表)

malloc/free

#include <iostream>
#include <cstdint>

using namespace std;

int main(int argc, char *argv[]) {
  int b1[4]{1, 2, 3, 4}; // 16 align
  int b2[5]{5, 4, 3, 2, 1};

  cout << b1 << " " << b2 << endl;

  //cout << sizeof(int) << endl; // 4
  cout << *(int *)((uint64_t)&b2 - sizeof(int)) << endl;

  return 0;
}

#include <iostream>
#include <cstdint>

using namespace std;

int main(int argc, char *argv[]) {

  int* p = (int *)malloc(4 * sizeof(int)); // p 在 stack上

  // 但以下数据在heap上
  p[0] = 1;
  p[1] = 1;
  p[2] = 1;
  p[3] = 1;

  free(p);

  return 0;
}

const char * 与 char *const

#include <iostream>
#include <cstdlib>
#include <cstdint>

using namespace std;

int main(int argc, char *argv[]) {

  char * const p = "hello world\0";
  const char * str = (char *)malloc(6);

  //p = str;
  //*(str+1) = 'l';
  str = p;

  cout << p << endl;
  cout << str << endl;

  return 0;
}

#include <iostream>
#include <cstdlib>
#include <cstdint>

using namespace std;

int main(int argc, char *argv[]) {

  char * str = (char *)malloc(6);
  str = "hello\0";


// size = 16 = 8 * 2 byte = 0x0000 0010
//  0000 0000
//  0000 0000
//  0000 0000
//  0000 0000
//  0000 0000
//  0000 0000
//  '\0'
//  'o'
//  ========= 8 byte对齐
//  'l'
//  'l'
//  'e'
//  'h'
//  0000 0000
//  0000 0000
//  0000 0000
//  0001 0001

//  6 / 16 = 0.375

  cout << str << endl;

  return 0;
}

heap 就是一个大数组

extern uint64_t heap_start_vaddr;
extern uint64_t heap_end_vaddr;

#define HEAP_MAX_SIZE (4096 * 1024) // 4MB
extern uint8_t heap[HEAP_MAX_SIZE];
#ifndef ALLOCATOR_H_
#define ALLOCATOR_H_

#include <alloca.h>
#include <cstdint>
#include <stdint.h>

extern uint64_t heap_start_vaddr;
extern uint64_t heap_end_vaddr;

#define HEAP_MAX_SIZE (4096 * 1024) // 4MB
extern uint8_t heap[HEAP_MAX_SIZE];

#define FREE (0)
#define ALLOCATED (1)
#define NIL (0)

#define MIN_EXPLICIT_FREE_LIST_BLOCKSIZE (16)
#define MIN_READBLACK_TREE_BLOCKSIZE (24)

// to allocate on physical page for heap(申请一个页表)
uint32_t extend_heap(uint32_t size);
void os_syscall_brk();

// round up
uint64_t round_up(uint64_t x, uint64_t n);

/*
 * operations for all blocks
 * */
// 获取/设置 blocksize
uint32_t get_blocksize(uint64_t header_vaddr);
void set_blocksize(uint64_t header_vaddr, uint32_t blocksize);

// 获取/设置 分配状态
uint32_t get_allocated(uint64_t header_vaddr);
void set_allocated(uint64_t header_vaddr, uint32_t allocated);

// 获取cookies
uint64_t get_payload(uint64_t vaddr);
uint64_t get_header(uint64_t vaddr);
uint64_t get_footer(uint64_t vaddr);

/*
 * operations for heap linked list
 * */

uint64_t get_nextheader(uint64_t vaddr);
uint64_t get_prevheader(uint64_t vaddr);

uint64_t get_prologue(); // 前言
uint64_t get_epilogue(); // 后记

uint64_t get_firstblock();
uint64_t get_lastblock();

int is_lastblock(uint64_t vaddr);
int is_firstblock(uint64_t vaddr);

// for free block as data structure
uint64_t get_field32_block_ptr(uint64_t header_vaddr, uint32_t min_blocksize,
                               uint32_t offset);
void set_field32_block_ptr(uint64_t header_vaddr, uint64_t block_ptr,
                           uint32_t min_blocksize, uint32_t offset);

// interface
int heap_init();
uint64_t mem_alloc(uint32_t size);
void mem_free(uint64_t vaddr);

#endif // ALLOCATOR_H_

block 的结构

高位
 ____________________
|___blocksize__|_A/F_| <- footer
|                    |
|                    |
|      payload       |
|                    |
|____________________|
|___blocksize__|_A/F_| <- header

低位

// start_of_heap
// (heap_start_vaddr)| [4(padding)] ->[8(header+footer)] [...]

// end_of_heap
// (heap_start_vaddr)| [4(padding)] [8(header+footer)] [...] ->[header] |(heap_end_vaddr)
 
#include "allocator.h"
#include <cassert>
#include <cstdint>
#include <iostream>

#define AF_BIT (0) // ALLOCATED / FREE
#define P8_BIT (1) // PREV BLOCK is a BLOCK 8
#define B8_BIT (2) // THIS BLOCK is 8 bytes


uint64_t round_up(uint64_t x, uint64_t n) { return n * ((x + n - 1) / n); }

// 设置第n位为1 H >> L
static void set_bit(uint64_t vaddr, int bit_offset) {
  uint32_t vector = 1 << bit_offset; // 000...1...000
  assert((vaddr & 0x3) == 0);        // 4对齐
  assert(get_prologue() <= vaddr && vaddr <= get_epilogue());
  *(uint32_t *)&heap[vaddr] |= vector;
}

// 将第n位清零 H >> L
static void reset_bit(uint64_t vaddr, int bit_offset) {
  uint32_t vector = 1 << bit_offset; // 000...1...000
  assert((vaddr & 0x3) == 0);        // 4对齐
  assert(get_prologue() <= vaddr && vaddr <= get_epilogue());
  *(uint32_t *)&heap[vaddr] &= (~vector); // 111...0...111
}

// 检查第n位是否为1 H >> L
static int is_bit_set(uint64_t vaddr, int bit_offset) {
  assert((vaddr & 0x3) == 0); // 4对齐
  assert(get_prologue() <= vaddr && vaddr <= get_epilogue());
  return (*(uint32_t *)&heap[vaddr] >> bit_offset) & 1;
}

static int is_block8(uint64_t vaddr) {
  if (vaddr == NIL || vaddr == get_epilogue()) {
    return 0;
  }
  assert(get_prologue() <= vaddr && vaddr <= get_epilogue());

  if (vaddr % 8 == 4) {
    // header
    if (is_bit_set(vaddr, B8_BIT) == 1) {
      return 1;
    }
  } else if (vaddr % 8 == 0) {
    // footer
    uint64_t next_header = vaddr + 4; // 下一个block的header_vaddr
    if (is_bit_set(next_header, B8_BIT) == 1) {
      return 1;
    }
  }
  return 0;
}

// start_of_heap
// (heap_start_vaddr)| [4(padding)] ->[8(header+footer)] [...]
uint64_t get_prologue() {
  assert(heap_end_vaddr > heap_start_vaddr);
  assert((heap_end_vaddr - heap_start_vaddr) % 4096 == 0); // 检查是否4k对齐
  assert(heap_start_vaddr % 4096 == 0);

  return heap_start_vaddr + sizeof(uint32_t);
}

// end_of_heap
// (heap_start_vaddr)| [4(padding)] [8(header+footer)] [...] ->[header]
// |(heap_end_vaddr)
uint64_t get_epilogue() {
  assert(heap_end_vaddr > heap_start_vaddr);
  assert((heap_end_vaddr - heap_start_vaddr) % 4096 == 0); // 检查是否4k对齐
  assert(heap_start_vaddr % 4096 == 0);

  return heap_end_vaddr - sizeof(uint32_t);
}

uint32_t get_blocksize(uint64_t header_vaddr) {
  if (header_vaddr == NIL) {
    return 0;
  }

  assert(get_prologue() <= header_vaddr &&
         header_vaddr <= get_epilogue()); // 在可用范围内
  assert((header_vaddr & 0x3) == 0x0);

  if (is_block8(header_vaddr) == 1) {
    return 8;
  } else {
    return (*((uint32_t *)&heap[header_vaddr]) &
            0xFFFFFFF8); // 000 prev_block_is_block_8| block_8| a/f
  }
}

void set_blocksize(uint64_t header_vaddr, uint32_t blocksize) {
  if (header_vaddr == NIL) {
    return;
  }
  assert(get_prologue() <= header_vaddr &&
         header_vaddr <= get_epilogue()); // 在可用范围内
  assert((header_vaddr & 0x3) == 0x0);
  assert((blocksize & 0x7) == 0x0);

  uint64_t next_header_vaddr;
  if (blocksize == 8) {
    // small block is special
    if (header_vaddr % 8 == 0) {
      // do not set footer of small block
      //  '\0'
      //  'a'
      //  'a'
      //  'a'
      //  0000 0000
      //  0000 0000
      //  0000 0000
      //  0100 0001 size == 8 这种就不设置footer了
      // reset to header
      header_vaddr = header_vaddr - 4;
    }
    next_header_vaddr = header_vaddr + 8;

    set_bit(header_vaddr, B8_BIT); // 设置该block的 8byte属性
    if (next_header_vaddr <= get_epilogue()) {
      set_bit(next_header_vaddr,
              P8_BIT); // 下一个block的前一个block是一个 BLOCK_8
    }

    if (get_allocated(header_vaddr) == FREE) {
      // free 8-byte does not set block size
      return;
    }
    // else, set header blocksize 8
  } else {
    if (header_vaddr % 8 == 4) {
      // header
      next_header_vaddr = header_vaddr + blocksize;
    } else {
      // footer
      next_header_vaddr = header_vaddr + 4;
    }
    reset_bit(header_vaddr, B8_BIT); // 当前block不是 BLOCK_8
    if (next_header_vaddr <= get_epilogue()) {
      reset_bit(next_header_vaddr,
                P8_BIT); // 下一个block的前一个block不是 BLOCK_8
    }
  }
  *(uint32_t *)&heap[header_vaddr] &= 0x00000007; // reset size 保留低3位
  *(uint32_t *)&heap[header_vaddr] |=
      blocksize; // set size blocksize 是8 对齐的 低3位是0
}

uint32_t get_allocated(uint64_t header_vaddr) {
  if (header_vaddr == NIL) {
    return ALLOCATED;
  }

  assert(get_prologue() <= header_vaddr &&
         header_vaddr <= get_epilogue()); // 在可用范围内
  assert((header_vaddr & 0x3) == 0x0);

  // 处理是footer的特殊情况 -> 该block是个 BLOCK_8
  // 没有footer不能直接取值需要前移到 header
  if (header_vaddr % 8 == 0) {
    // footer
    // check if 8-byte small block
    uint64_t next_header_vaddr = header_vaddr + 4;
    if (next_header_vaddr <= get_epilogue()) {
      // check P8 bit of next
      if (is_bit_set(next_header_vaddr, P8_BIT) == 1) {
        // current block is 8-byte, no footer. check header instead
        header_vaddr -= 4;
      }
      // else, current block has footer
    } else {
      // this is block is epilogue but it's 8X
      assert(0);
    }
  }

  return (*((uint32_t *)&heap[header_vaddr]) & 0x1);
}

void set_allocated(uint64_t header_vaddr, uint32_t allocated) {
  if (header_vaddr == NIL) {
    return;
  }
  assert(get_prologue() <= header_vaddr &&
         header_vaddr <= get_epilogue()); // 在可用范围内
  assert((header_vaddr & 0x3) == 0x0);

  if (header_vaddr % 8 == 0) {
    // check if 8-bytes small block
    uint64_t next_header_vaddr = header_vaddr + 4;

    if (next_header_vaddr <= get_epilogue()) {
      // check P8 bit of next
      if (is_bit_set(next_header_vaddr, P8_BIT) == 1) {
        header_vaddr -= 4;
      }
      // else, current blocks has footer
    } else {
      assert(0);
    }
  }
  *(uint32_t *)&heap[header_vaddr] &=
      0xFFFFFFFE; // reset allocated 保留所有高位
  *(uint32_t *)&heap[header_vaddr] |= (allocated & 0x1);
}

// 传入 void * 或者 header都可以
uint64_t get_payload(uint64_t vaddr) {
  if (vaddr == NIL) {
    return NIL;
  }
  assert(get_prologue() <= vaddr && vaddr <= get_epilogue());
  assert((vaddr & 0x3) == 0); // 必须是4对齐
  return round_up(vaddr, 8);
}

uint64_t get_header(uint64_t vaddr) {
  if (vaddr == NIL) {
    return NIL;
  }
  assert(get_prologue() <= vaddr && vaddr <= get_epilogue());
  assert((vaddr & 0x3) == 0); // 必须是4对齐
  return round_up(vaddr, 8) - 4;
}

uint64_t get_footer(uint64_t vaddr) {
  if (vaddr == NIL) {
    return NIL;
  }
  assert(get_prologue() <= vaddr && vaddr <= get_epilogue());
  assert(vaddr % 8 == 4);
  // vaddr can be:
  // 1. starting address of the block (8 * n + 4)
  // 2. starting address of the payload (8 * m)
  assert(vaddr % 8 == 4);

  uint64_t header_vaddr = get_header(vaddr);
  uint64_t footer_vaddr = header_vaddr + get_blocksize(header_vaddr) - 4;

  assert(get_firstblock() < footer_vaddr && footer_vaddr < get_epilogue());
  assert(footer_vaddr % 8 == 0);
  return footer_vaddr;
}

uint64_t get_nextheader(uint64_t vaddr) {
  if (vaddr == NIL || vaddr == get_epilogue()) {
    return NIL;
  }
  assert(get_prologue() <= vaddr && vaddr <= get_epilogue());

  uint64_t header_vaddr = get_header(vaddr);
  uint32_t block_size = get_blocksize(header_vaddr);

  uint64_t next_header_vaddr = header_vaddr + block_size;
  assert(get_firstblock() < next_header_vaddr && next_header_vaddr <= get_epilogue());

  return next_header_vaddr;
}

uint64_t get_prevheader(uint64_t vaddr) {
  if (vaddr == NIL || vaddr == get_prologue()) {
    return NIL;
  }
  assert(get_prologue() <= vaddr && vaddr <= get_epilogue());
  uint64_t header_vaddr = get_header(vaddr);
  uint64_t prev_header_vaddr;

  // check P8 bit 0010
  if (is_bit_set(header_vaddr, P8_BIT) == 1) {
    // prev block is a BLOCK_8
    prev_header_vaddr = header_vaddr - 8;
    return prev_header_vaddr;
  } else {
    // > 8
    uint64_t prev_footer_vaddr = header_vaddr - 4;
    uint32_t prev_blocksize = get_blocksize(prev_footer_vaddr);

    prev_header_vaddr = header_vaddr - prev_blocksize;
    assert(get_prologue() <= prev_header_vaddr && prev_header_vaddr < get_epilogue());
    assert(get_blocksize(prev_header_vaddr) == get_blocksize(prev_footer_vaddr));
    assert(get_allocated(prev_header_vaddr) == get_allocated(prev_footer_vaddr));

    return prev_header_vaddr;
  }
}

// 返回第一个有效block的header
// (start)| [4(padding)] [8(the_prologue_block)] ->[header...footer] [...] [header] |(end)
uint64_t get_firstblock() {
  assert(heap_end_vaddr > heap_start_vaddr);
  assert((heap_end_vaddr - heap_start_vaddr) % 4096 == 0); // 检查是否4k对齐
  assert(heap_start_vaddr % 4096 == 0);

  // 4 for the not in use
  // 8 for the prologue block
  return get_prologue() + 8;
}

// 返回最后一个有效block的header
// (start)| [4(padding)] [8(the_prologue_block)] [...] ->[header...footer] [header] |(end)
uint64_t get_lastblock() {
  assert(heap_end_vaddr > heap_start_vaddr);
  assert((heap_end_vaddr - heap_start_vaddr) % 4096 == 0); // 检查是否4k对齐
  assert(heap_start_vaddr % 4096 == 0);

  uint64_t epilogue_header = get_epilogue();
  return get_prevheader(epilogue_header);
}

int is_firstblock(uint64_t vaddr) {
  if (vaddr == NIL) {
    return 0;
  }
  // vaddr can be:
  // 1. starting address of the block (8 * n + 4)
  // 2. starting address of the payload (8 * m)
  assert(get_firstblock() <= vaddr && vaddr < get_epilogue());
  assert((vaddr & 0x3) == 0x0);

  uint64_t header_vaddr = get_header(vaddr);

  if (header_vaddr == get_firstblock()) {
    return 1;
  }
  return 0;
}

int is_lastblock(uint64_t vaddr) {
  if (vaddr == NIL) {
    return 0;
  }
  assert(get_firstblock() <= vaddr && vaddr < get_epilogue());
  assert((vaddr & 0x3) == 0x0);

  uint64_t header_vaddr = get_header(vaddr);
  uint32_t blocksize = get_blocksize(header_vaddr);

  if (header_vaddr + blocksize == get_epilogue()) {
    return 1;
  }
  return  0;
}

uint64_t get_field32_block_ptr(uint64_t header_vaddr, uint32_t min_blocksize,
                               uint32_t offset) {
  if (header_vaddr == NIL) {
    return NIL;
  }

  assert(get_firstblock() <= header_vaddr && header_vaddr <= get_lastblock());
  assert(header_vaddr % 8 == 4);
  assert(get_blocksize(header_vaddr) >= min_blocksize);

  assert(offset % 4 == 0);

  uint32_t vaddr_32 = *(uint32_t *)&heap[header_vaddr + offset];
  return (uint64_t)vaddr_32;
}

void set_field32_block_ptr(uint64_t header_vaddr, uint64_t block_ptr,
                           uint32_t min_blocksize, uint32_t offset) {
  if (header_vaddr == NIL) {
    return;
  }

  assert(get_firstblock() <= header_vaddr && header_vaddr <= get_lastblock());
  assert(header_vaddr % 8 == 4);
  assert(get_blocksize(header_vaddr) >= min_blocksize);

  assert(block_ptr == NIL ||
         (get_firstblock() <= block_ptr && block_ptr <= get_lastblock()));
  assert(block_ptr == NIL || block_ptr % 8 == 4);
  assert(block_ptr == NIL || get_blocksize(block_ptr) >= min_blocksize);

  assert(offset % 4 == 0);

  // actually a 32-bit pointer
  assert((block_ptr >> 32) == 0);
  *(uint32_t *)&heap[header_vaddr + offset] = (uint32_t)(block_ptr & 0xFFFFFFFF);
}

malloc / free

#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <iostream>

#include "allocator.h"

#define IMPLICIT_FREE_LIST

uint64_t heap_start_vaddr;
uint64_t heap_end_vaddr;
uint8_t heap[HEAP_MAX_SIZE];

/* ------------------------------------- */
/*  Debugging and Correctness Checking   */
/* ------------------------------------- */

// 检查heap
void check_heap_correctness() {
  int linear_free_counter = 0;
  uint64_t p = get_firstblock();
  while (p != NIL && p <= get_lastblock()) {
    assert(p % 8 == 4);
    assert(get_firstblock() <= p && p <= get_lastblock());

    uint64_t f = get_footer(p);
    uint32_t blocksize = get_blocksize(p);
    if (blocksize != 8) {
      assert(get_blocksize(p) == get_blocksize(f));
      assert(get_allocated(p) == get_allocated(f));
    }

    // rule 1: block[0] ==> A/F
    // rule 2: block[-1] ==> A/F
    // rule 3: block[i] == A ==> block[i-1] == A/F && block[i+1] == A/F
    // rule 4: block[i] == F ==> block[i-1] == A && block[i+1] == A
    // these 4 rules ensures that
    // adjacent free blocks are always merged together
    // henceforth external fragmentation are minimized
    if (get_allocated(p) == FREE) {
      linear_free_counter += 1;
    } else {
      linear_free_counter = 0;
    }
    assert(linear_free_counter <= 1);

    p = get_nextheader(p);
  }
}

static void block_info_print(uint64_t h) {
  uint32_t a = get_allocated(h);
  uint32_t s = get_blocksize(h);
  uint64_t f = get_footer(h);

  uint32_t hv = *(uint32_t *)&heap[h];
  uint32_t fv = *(uint32_t *)&heap[f];

  uint32_t p8 = (hv >> 1) & 0x1;
  uint32_t b8 = (hv >> 2) & 0x1;
  uint32_t rb = (fv >> 1) & 0x1;

  printf("H:%lu,\tF:%lu,\tS:%u,\t(A:%u,RB:%u,B8:%u,P8:%u)\n", h, f, s, a, rb,
         b8, p8);
}

static void heap_blocks_print() {
  printf("============\nheap blocks:\n");
  uint64_t h = get_firstblock();
  int i = 0;
  while (i < (HEAP_MAX_SIZE / 8) && h != NIL && h < get_epilogue()) {
    block_info_print(h);
    h = get_nextheader(h);
  }
  printf("============\n");
}

/*================================*/
/*          向OS申请内存          */
/*================================*/
void os_syscall_brk() {}

uint32_t extend_heap(uint32_t size) {
  size = (uint32_t)round_up((uint64_t)size, 4096);
  if (heap_start_vaddr - heap_start_vaddr+ size <= HEAP_MAX_SIZE) {
    os_syscall_brk();  // 缺页异常
    heap_end_vaddr += size;
  } else {
    return 0;
  }
  uint64_t epilogue = get_epilogue();
  set_allocated(epilogue, ALLOCATED);
  set_blocksize(epilogue, 0);

  return size;
}

/* ------------------------------------- */
/*            各种不同的实现             */
/* ------------------------------------- */
// ===============Implicit Free List=================
#ifdef IMPLICIT_FREE_LIST
int implicit_list_initialize_free_block();
uint64_t implicit_list_search_free_block(uint32_t payload_size, uint32_t *alloc_blocksize);
int implicit_list_insert_free_block(uint64_t free_header);
int implicit_list_delete_free_block(uint64_t free_header);
void implicit_list_check_free_block();
#endif

// ===============Explicit Free List=================
#ifdef EXPLICIT_FREE_LIST
int explicit_list_initialize_free_block();
uint64_t explicit_list_search_free_block(uint32_t payload_size, uint32_t *alloc_blocksize);
int explicit_list_insert_free_block(uint64_t free_header);
int explicit_list_delete_free_block(uint64_t free_header);
void explicit_list_check_free_block();
#endif

// ===============Redblack Tree Free=================
#ifdef REDBLACK_TREE
int redblack_tree_initialize_free_block();
uint64_t redblack_tree_search_free_block(uint32_t payload_size, uint32_t *alloc_blocksize);
int redblack_tree_insert_free_block(uint64_t free_header);
int redblack_tree_delete_free_block(uint64_t free_header);
void redblack_tree_check_free_block();
#endif

static int initialize_free_block()
{
#ifdef IMPLICIT_FREE_LIST
    return implicit_list_initialize_free_block();
#endif

#ifdef EXPLICIT_FREE_LIST
    return explicit_list_initialize_free_block();
#endif

#ifdef REDBLACK_TREE
    return redblack_tree_initialize_free_block();
#endif
}

static uint64_t search_free_block(uint32_t payload_size, uint32_t *alloc_blocksize)
{
#ifdef IMPLICIT_FREE_LIST
    return implicit_list_search_free_block(payload_size, alloc_blocksize);
#endif

#ifdef EXPLICIT_FREE_LIST
    return explicit_list_search_free_block(payload_size, alloc_blocksize);
#endif

#ifdef REDBLACK_TREE
    return redblack_tree_search_free_block(payload_size, alloc_blocksize);
#endif
}

static int insert_free_block(uint64_t free_header)
{
#ifdef IMPLICIT_FREE_LIST
    return implicit_list_insert_free_block(free_header);
#endif

#ifdef EXPLICIT_FREE_LIST
    return explicit_list_insert_free_block(free_header);
#endif

#ifdef REDBLACK_TREE
    return redblack_tree_insert_free_block(free_header);
#endif
}

static int delete_free_block(uint64_t free_header)
{
#ifdef IMPLICIT_FREE_LIST
    return implicit_list_delete_free_block(free_header);
#endif

#ifdef EXPLICIT_FREE_LIST
    return explicit_list_delete_free_block(free_header);
#endif

#ifdef REDBLACK_TREE
    return redblack_tree_delete_free_block(free_header);
#endif
}

static void check_free_block()
{
#ifdef IMPLICIT_FREE_LIST
    implicit_list_check_free_block();
#endif

#ifdef EXPLICIT_FREE_LIST
    explicit_list_check_free_block();
#endif

#ifdef REDBLACK_TREE
    redblack_tree_check_free_block();
#endif
}

/* ------------------------------------- */
/*       Malloc and Free 的具体实现      */
/* ------------------------------------- */
static uint64_t merge_blocks_as_free(uint64_t low, uint64_t high) {
  assert(low % 8 == 4);
  assert(high % 8 == 4);
  assert(get_firstblock() <= low && low < get_lastblock());
  assert(get_firstblock() < high && high <= get_lastblock());
  assert(get_nextheader(low) == high);
  assert(get_prevheader(high) == low);

  // must merge as free
  uint32_t blocksize = get_blocksize(low) + get_blocksize(high);

  set_blocksize(low, blocksize);
  set_allocated(low, FREE);

  uint64_t footer = get_footer(low);
  set_blocksize(footer, blocksize);
  set_allocated(footer, FREE);

  return low;
}

// 传入的是某个block的header 尝试 allocate 后进行 split
// 返回payload_vaddr 不是 header
// [(request_blocksize) (leftsize)] <- 这是一个free block 即将 被分配
static uint64_t try_alloc_with_splitting(uint64_t block_vaddr, uint32_t request_blocksize) {
  if (request_blocksize < 8) {
    return NIL; // 上一部内存对齐失败了
  }

  uint64_t b = block_vaddr;
  uint32_t b_blocksize = get_blocksize(b);
  uint32_t b_allocated = get_allocated(b);

  if (b_allocated == FREE && b_blocksize >= request_blocksize) {
    // allocate this block
    delete_free_block(b);
    uint64_t left_footer = get_footer(b); // b 原本的footer

    // set the header
    set_allocated(b, ALLOCATED);
    set_blocksize(b, request_blocksize);

    // set the footer
    uint64_t b_footer = b + request_blocksize - 4;
    set_allocated(b_footer, ALLOCATED);
    set_blocksize(b_footer, request_blocksize);

    uint32_t left_size = b_blocksize - request_blocksize;
    if (left_size >= 8) {
      // split the left space
      uint64_t left_header = get_nextheader(b);
      set_allocated(left_header, FREE);
      set_blocksize(left_header, left_size);

      set_allocated(left_footer, FREE);
      set_blocksize(left_footer, left_size);

      assert(get_footer(left_header) == left_footer);
      // TODO 分析下面函数
      insert_free_block(left_header);
    }
    return get_payload(b);
  }
  return NIL;
}

static uint64_t try_extend_heap_to_alloc(uint32_t size) {
  // get the size to be added
  uint64_t old_last = get_lastblock();
  uint32_t last_allocated = get_allocated(old_last);
  uint32_t last_blocksize = get_blocksize(old_last);

  uint32_t to_request_from_OS = size;
  if (last_allocated == FREE) {
    // last block can help the request
    to_request_from_OS -= last_blocksize;
    delete_free_block(old_last); // 从free_list上摘除
  }

  uint64_t old_epilogue = get_epilogue();

  uint32_t os_allocated_size = extend_heap(to_request_from_OS); // 一开始只有4096
  if (os_allocated_size != 0) {
    assert(os_allocated_size >= 4096); // TODO 这里限制了最大申请量 后续处理一下
    assert(os_allocated_size % 4096 == 0);

    uint64_t payload_header = NIL;

    if (last_allocated == ALLOCATED) {
      // no need to merge
      // take place the old epilogue as new lastblock
      uint64_t new_last = old_epilogue;
      set_allocated(new_last, FREE);
      set_blocksize(new_last, os_allocated_size);

      // set the new footer
      uint64_t new_last_footer = get_footer(new_last);
      set_allocated(new_last_footer, FREE);
      set_blocksize(new_last_footer, os_allocated_size);
      insert_free_block(new_last);

      payload_header = new_last;
    } else {
      // need to merge
      set_allocated(old_last, FREE); // make sure the last block is free
      set_blocksize(old_last, last_blocksize + os_allocated_size);

      uint64_t last_footer = get_footer(old_last);
      set_allocated(last_footer, FREE);
      set_blocksize(last_footer, last_blocksize + os_allocated_size);
      insert_free_block(old_last);

      payload_header = old_last;
    }

    // try to allocate
    uint64_t payload_vaddr = try_alloc_with_splitting(payload_header, size);
    if (payload_header != NIL) {
      return payload_vaddr;
    }
  }

  if (last_allocated == FREE) {
    insert_free_block(old_last); // 把刚才取出来的freeblock放回去
  }
  return NIL;
}

#define DEBUG
/*--------------------------------------*/
/*            对外暴露的函数            */
/*--------------------------------------*/
int heap_init() {
  // reset all to 0
  for (int i = 0; i < HEAP_MAX_SIZE; i += 8) {
    *(uint64_t *)&heap[i] = 0;
  }

  heap_start_vaddr = 0;
  heap_end_vaddr = 4096;

  // A epilogue
  // F free block
  // A prologue

  // set the prologue block
  uint64_t prologue_header = get_prologue();
  set_allocated(prologue_header, ALLOCATED);
  set_blocksize(prologue_header, 8);

  uint64_t prologue_footer = prologue_header + 4;
  set_allocated(prologue_footer, ALLOCATED);
  set_blocksize(prologue_footer, 8);

  // set the epilogue block
  // it is a footer only
  uint64_t epilogue = get_epilogue();
  set_allocated(epilogue, ALLOCATED);
  set_blocksize(epilogue, 0);

  // set the block size & allocated of the only regular block
  uint64_t first_header = get_firstblock();
  set_allocated(first_header, FREE);
  set_blocksize(first_header, 4096 - 4 - 8 - 4);

  uint64_t first_footer = get_footer(first_header);
  set_allocated(first_footer, FREE);
  set_blocksize(first_footer, 4096 - 4 - 8 - 4);

  initialize_free_block();

#ifdef DEBUG
  heap_blocks_print();
#endif
  return 1;
}

uint64_t mem_alloc(uint32_t size) {
  assert(0 < size && size < HEAP_MAX_SIZE - 4 - 8 - 4);

  uint32_t alloc_blocksize = 0;
  uint64_t payload_header = search_free_block(size, &alloc_blocksize); // 要size给alloc_blocksize
  uint64_t payload_vaddr = NIL;

  if (payload_header != NIL) {
#ifdef DEBUG
    printf("找到了空闲\n");
#endif
    payload_vaddr = try_alloc_with_splitting(payload_header, alloc_blocksize);
    assert(payload_vaddr != NIL);
  } else {
#ifdef DEBUG
    printf("没找到空闲\n");
#endif
    payload_vaddr = try_extend_heap_to_alloc(alloc_blocksize);
  }
#ifdef DEBUG
    check_heap_correctness();
    check_free_block();
    heap_blocks_print();
#endif
  return payload_vaddr;
}

void mem_free(uint64_t payload_vaddr) {
  if (payload_vaddr == NIL) {
    return;
  }

  // get_firstblock 返回的是 第一个block的header 不是 payload
  assert(get_firstblock() < payload_vaddr && payload_vaddr < get_epilogue());
  assert((payload_vaddr & 0x7) == 0x0);

  // request can be first or last block
  uint64_t req = get_header(payload_vaddr);
  uint64_t req_footer = get_footer(req); // for last block, it is 0

  // get the block_header and allocated of next & prev blocks
  uint64_t next = get_nextheader(req);
  uint64_t prev = get_prevheader(req);
  uint32_t next_allocated = get_allocated(next);
  uint32_t prev_allocated = get_allocated(prev);

  if (next_allocated == ALLOCATED && prev_allocated == ALLOCATED) {
    // case 1 [A|(A->F)|A]
    set_allocated(req, FREE);
    set_allocated(req_footer, FREE);

    insert_free_block(req);
  } else if (next_allocated == FREE && prev_allocated == ALLOCATED) {
    // case 2 [A|(A->F)|F|A] => [A|F+F|A]
    delete_free_block(next);

    uint64_t one_free = merge_blocks_as_free(req, next);

    insert_free_block(one_free);
  } else if (next_allocated == ALLOCATED && prev_allocated == FREE) {
    // case 3 [A|F|(A->F)|A] => [A|F+F|A]
    delete_free_block(prev);

    uint64_t one_free = merge_blocks_as_free(prev, req);

    insert_free_block(one_free);
  } else if (next_allocated == FREE && prev_allocated == FREE) {
    // case 4 [A|F|(A->F)|F|A]
    delete_free_block(prev);
    delete_free_block(next);

    uint64_t one_free = merge_blocks_as_free(merge_blocks_as_free(prev, req), next);

    insert_free_block(one_free);
  } else {
    assert(0);
  }
#ifdef DEBUG
  printf("释放空间\n");
    check_heap_correctness();
    check_free_block();
    heap_blocks_print();
#endif
}

隐式空闲链表

数据结构

// 所谓的 内存链表管理都是建立在 heap[MAX_HEAP_SIZE] 上的
// 对于 implicit_list 而言
// [header...footer | header...footer | header...footer]
// 其实就是直接操作这个数组 使用 header/footer +/- blocksize 实现一个抽象的单向链表


实现

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "allocator.h"
#include "algorithm.h"
#include "block_list.h"

// 所谓的 内存链表管理都是建立在 heap[MAX_HEAP_SIZE] 上的
// 对于 implicit_list 而言
// [header...footer | header...footer | header...footer]
// 其实就是直接操作这个数组 使用 header/footer +/- blocksize 实现一个抽象的单向链表

// 外部引入的 block_list
extern linkedlist_internal_t block_list;

// Manage block blocks
#define MIN_IMPLICIT_FREE_LIST_BLOCKSIZE (8)

int implicit_list_initialize_free_block()
{
  // init block block list
  block_list_init();
  return 1;
}

uint64_t implicit_list_search_free_block(uint32_t payload_size, uint32_t *alloc_blocksize)
{
  // search 8-byte block list
  if (payload_size <= 4 && block_list.count != 0) {
    // a block block and 8-byte list is not empty
    *alloc_blocksize = 8;
    return block_list.head;
  }
    
  uint32_t free_blocksize = round_up(payload_size, 8) + 4 + 4; // 8对齐+header_footer
  *alloc_blocksize = free_blocksize;

  // search the whole heap
  uint64_t b = get_firstblock();
  while (b <= get_lastblock()) {
    uint32_t b_blocksize = get_blocksize(b);
    uint32_t b_allocated = get_allocated(b);

    if (b_allocated == FREE && free_blocksize <= b_blocksize) {
      return b;
    } else {
      b = get_nextheader(b);
    }
  }

  return NIL;
}

int implicit_list_insert_free_block(uint64_t free_header)
{
  assert(free_header % 8 == 4);
  assert(get_firstblock() <= free_header && free_header <= get_lastblock());
  assert(get_allocated(free_header) == FREE);

  uint32_t blocksize = get_blocksize(free_header);
  assert(blocksize % 8 == 0);
  assert(blocksize >= 8);

  switch (blocksize)
  {
  case 8:
    block_list_insert(free_header);
    break;
        
  default:
    break;
  }

  return 1;
}

int implicit_list_delete_free_block(uint64_t free_header)
{
  assert(free_header % 8 == 4);
  assert(get_firstblock() <= free_header && free_header <= get_lastblock());
  assert(get_allocated(free_header) == FREE);

  uint32_t blocksize = get_blocksize(free_header);
  assert(blocksize % 8 == 0);
  assert(blocksize >= 8);

  switch (blocksize)
  {
  case 8:
    block_list_delete(free_header);
    break;
        
  default:
    break;
  }

  return 1;
}

void implicit_list_check_free_block()
{
  block_list_check_free_blocks();
}

显式空闲链表

数据结构

// 所谓的 内存链表管理都是建立在 heap[MAX_HEAP_SIZE] 上的
// 对于 explicit_list 而言
// 是维护了如下的一个free_list
//
//   ____   ________________prev___________   ____________prev_________________   ______prev____
//       | V                               | V                                 | V
// [...header.F.footer | header.A.footer | header.F.footer | header.A.footer | header.F.footer...]
//  ___^ |_____________next________________^  |________________next____________^ |______next____
//
// 遍历的时候只找这个 free_list 找到一个block_size >= request_size


实现

#include "algorithm.h"
#include "allocator.h"
#include "block_list.h"
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

// 所谓的 内存链表管理都是建立在 heap[MAX_HEAP_SIZE] 上的
// 对于 explicit_list 而言
// 是维护了如下的一个free_list
//
//   ____   ________________prev___________   ____________prev_________________   ______prev____
//       | V                               | V                                 | V
// [...header.F.footer | header.A.footer | header.F.footer | header.A.footer | header.F.footer...]
//  ___^ |_____________next________________^  |________________next____________^ |______next____
//
// 遍历的时候只找这个 free_list 找到一个block_size >= request_size

extern linkedlist_internal_t block_list;

/* ------------------------------------- */
/*  Operations for List Block Structure  */
/* ------------------------------------- */

static int compare_nodes(uint64_t first, uint64_t second) {
  return !(first == second);
}

static int is_null_node(uint64_t node_id) { return node_id == NULL_ID; }

static uint64_t get_prevfree(uint64_t header_vaddr) {
  return get_field32_block_ptr(header_vaddr, MIN_EXPLICIT_FREE_LIST_BLOCKSIZE,
                               4);
}

uint64_t get_nextfree(uint64_t header_vaddr) {
  return get_field32_block_ptr(header_vaddr, MIN_EXPLICIT_FREE_LIST_BLOCKSIZE,
                               8);
}

static int set_prevfree(uint64_t header_vaddr, uint64_t prev_vaddr) {
  set_field32_block_ptr(header_vaddr, prev_vaddr,
                        MIN_EXPLICIT_FREE_LIST_BLOCKSIZE, 4);
  return 1;
}

static int set_nextfree(uint64_t header_vaddr, uint64_t next_vaddr) {
  set_field32_block_ptr(header_vaddr, next_vaddr,
                        MIN_EXPLICIT_FREE_LIST_BLOCKSIZE, 8);
  return 1;
}

// register the 5 functions above to be called by the linked list framework
static linkedlist_node_interface i_free_block = {
    .is_null_node = &is_null_node,
    .compare_nodes = &compare_nodes,
    .get_node_prev = &get_prevfree,
    .set_node_prev = &set_prevfree,
    .get_node_next = &get_nextfree,
    .set_node_next = &set_nextfree,
};

/* ------------------------------------- */
/*  Operations for Linked List           */
/* ------------------------------------- */

static int update_head(linkedlist_internal_t *this_pointer,
                       uint64_t block_vaddr) {
  if (this_pointer == NULL) {
    return 0;
  }

  assert(block_vaddr == NULL_ID ||
         (get_firstblock() <= block_vaddr && block_vaddr <= get_lastblock()));
  assert(block_vaddr == NULL_ID || block_vaddr % 8 == 4);
  assert(block_vaddr == NULL_ID ||
         get_blocksize(block_vaddr) >= MIN_EXPLICIT_FREE_LIST_BLOCKSIZE);

  this_pointer->head = block_vaddr;
  return 1;
}

// The explicit free linked list
linkedlist_internal_t explicit_list;

void explist_list_init() {
  explicit_list.head = NULL_ID;
  explicit_list.count = 0;
  explicit_list.update_head = &update_head;
}

uint64_t explicit_list_search(uint32_t free_blocksize) {
  // search explicit free list
  uint64_t b = explicit_list.head;
  uint32_t counter_copy = explicit_list.count;
  for (int i = 0; i < counter_copy; ++i) {
    uint32_t b_blocksize = get_blocksize(b);
    uint32_t b_allocated = get_allocated(b);

    if (b_allocated == FREE && free_blocksize <= b_blocksize) {
      return b;
    } else {
      b = get_nextfree(b);
    }
  }

  return NIL;
}

void explicit_list_insert(uint64_t free_header) {
  assert(get_firstblock() <= free_header && free_header <= get_lastblock());
  assert(free_header % 8 == 4);
  assert(get_blocksize(free_header) >= MIN_EXPLICIT_FREE_LIST_BLOCKSIZE);
  assert(get_allocated(free_header) == FREE);

  linkedlist_internal_insert(&explicit_list, &i_free_block, free_header);
}

void explicit_list_delete(uint64_t free_header) {
  assert(get_firstblock() <= free_header && free_header <= get_lastblock());
  assert(free_header % 8 == 4);
  assert(get_blocksize(free_header) >= MIN_EXPLICIT_FREE_LIST_BLOCKSIZE);
  // assert(get_allocated(free_header) == FREE);

  linkedlist_internal_delete(&explicit_list, &i_free_block, free_header);
  set_prevfree(free_header, NIL);
  set_nextfree(free_header, NIL);
}

/* ------------------------------------- */
/*  For Debugging                        */
/* ------------------------------------- */

// from segregated list
extern void check_size_list_correctness(linkedlist_internal_t *list,
                                        linkedlist_node_interface *i_node,
                                        uint32_t min_size, uint32_t max_size);

static void explicit_list_print() {
  uint64_t p = explicit_list.head;
  printf("explicit free list <{%lu},{%lu}>:\n", explicit_list.head,
         explicit_list.count);
  for (int i = 0; i < explicit_list.count; ++i) {
    printf("<%lu:%u/%u> ", p, get_blocksize(p), get_allocated(p));
    p = get_nextfree(p);
  }
  printf("\n");
}

void check_block16_correctness() {
  check_size_list_correctness(&explicit_list, &i_free_block, 16, 16);
}

/* ------------------------------------- */
/*  Implementation                       */
/* ------------------------------------- */

int explicit_list_initialize_free_block() {
  uint64_t first_header = get_firstblock();

  set_prevfree(first_header, first_header);
  set_nextfree(first_header, first_header);

  explist_list_init();
  explicit_list_insert(first_header);

  // init block block list
  block_list_init();

  return 1;
}

uint64_t explicit_list_search_free_block(uint32_t payload_size,
                                         uint32_t *alloc_blocksize) {
  // search 8-byte block list
  if (payload_size <= 4) {
    // a block block
    *alloc_blocksize = 8;

    if (block_list.count != 0) {
      // 8-byte list is not empty
      return block_list.head;
    }
  } else {
    *alloc_blocksize = round_up(payload_size, 8) + 4 + 4;
    assert((*alloc_blocksize) >= MIN_EXPLICIT_FREE_LIST_BLOCKSIZE);
  }

  // search explicit free list
  return explicit_list_search(*alloc_blocksize);
}

int explicit_list_insert_free_block(uint64_t free_header) {
  assert(free_header % 8 == 4);
  assert(get_firstblock() <= free_header && free_header <= get_lastblock());
  assert(get_allocated(free_header) == FREE);

  uint32_t blocksize = get_blocksize(free_header);
  assert(blocksize % 8 == 0);
  assert(blocksize >= 8);

  switch (blocksize) {
  case 8:
    block_list_insert(free_header);
    break;

  default:
    explicit_list_insert(free_header);
    break;
  }

  return 1;
}

int explicit_list_delete_free_block(uint64_t free_header) {
  assert(free_header % 8 == 4);
  assert(get_firstblock() <= free_header && free_header <= get_lastblock());
  assert(get_allocated(free_header) == FREE);

  uint32_t blocksize = get_blocksize(free_header);
  assert(blocksize % 8 == 0);
  assert(blocksize >= 8);

  switch (blocksize) {
  case 8:
    block_list_delete(free_header);
    break;

  default:
    explicit_list_delete(free_header);
    break;
  }

  return 1;
}

void explicit_list_check_free_block() {
  block_list_check_free_blocks();
  check_size_list_correctness(&explicit_list, &i_free_block, 16, 0xFFFFFFFF);
}

红黑树

不会红黑树 现在先学抽象的内存管理 之后补上

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值