实现一个动态存储分配

如何自己实现一个动态存储的分配机制,当然有很多的存储的分配方法,关键在于“堆”的管理。

这里我们使用“隐式链表”的方法实现对“堆”的分配。

而且分配的单位是“字”,这里的字是4个字节,而且我们分配的内存都按8字节(也就是双字)对齐。

上图中一个空格代表一个字(4字节)

也就是我们的堆开始三个字是堆的对齐和头部用的。最后是堆的尾。

上图是我们堆的“分配块”的头部,由于我们的堆是以8字节对齐的,也就是分配的最小单位将是双字,于是我们知道对于长度来讲

最后三个位是没用的。因为必须是8的倍数嘛,于是我们可以用这几位来作标记看是否己经分配了该块。

块的头部和尾部是一样的。

我们这里采用“首次匹配”策略进行块的分配。也就是说我们从“堆”的头部开始搜索合适的块,当有块的大小大于要求的块大小时,我们就将当空的空块分割一块出来分配给它。

当整个“堆”没有合适的块时,我们在“堆”的后面申请新的块。


  1. #ifndef DYNAMIC_MALLOC_H
  2. #define DYNAMIC_MALLOC_H
  3. #define NoFault 0
  4. #define OutofMemory 1
  5. #define NoRest 2
  6. class DynamicMalloc{
  7. protected:
  8. const static int WSIZE=4;
  9. const static int DSIZE=8;
  10. const static bool ALLOCED=1;
  11. const static bool UNALLOCED=0;
  12. private:
  13. static char* mem_heap; //指向堆首地址
  14. static char* mem_brk; //指向目前分配的“堆”的最后一个字的下一个
  15. static char* mem_max_addr; //一直指向最大所能分配的地址,“堆大小”
  16. static char* heap_listp; //一直指向序言块
  17. const static unsigned int MAX_HEAP=2048;
  18. const static unsigned int CHUNKSIZE=30;
  19. const static unsigned int MINCHUNK=DSIZE*2+2*WSIZE;
  20. unsigned int pack(unsigned int size,unsigned int alloc){
  21. return size|alloc;
  22. }
  23. void put_data(void *ptr,unsigned int val){
  24. *((unsigned int*)ptr)=val;
  25. }
  26. unsigned int get_data(void *ptr){
  27. return *((unsigned int*)(ptr));
  28. }
  29. unsigned int get_size(void *ptr){//取出块大小
  30. return get_data(ptr)&(~0x07);
  31. }
  32. bool get_alloced(void *ptr){//取出“分配”标志
  33. return get_data(ptr)&0x01;
  34. }
  35. char* mem_head(void *ptr){//找到块的头部
  36. return (char*)ptr-WSIZE;
  37. }
  38. char* mem_ftrp(void *ptr){ //找到块的尾部
  39. return (char*)ptr+get_size((void*)mem_head(ptr));
  40. }
  41. char* next_blkb(void *ptr){//找到下一块
  42. return (char*)ptr+get_size((void*)mem_head(ptr))+DSIZE;
  43. }
  44. char *pre_blkb(void *ptr){//找到前面块
  45. return (char*)ptr-get_size((void*)((char*)ptr-DSIZE))-DSIZE;
  46. }
  47. void *mem_sbrk(unsigned int inc);
  48. void mm_init();
  49. void* extern_heap(unsigned int size);
  50. void coalesce(void *ptr);
  51. void clearBlock(void *ptr);
  52. void* find_fit(unsigned int size);
  53. public:
  54. int mem_errno;
  55. DynamicMalloc();
  56. void* mm_malloc(unsigned int size);
  57. void mm_free(void *ptr);
  58. };
  59. #endif

  1. #include<stdio.h>
  2. #include<memory>
  3. #include<iostream>
  4. #include"DynamicMalloc.h"
  5. char * DynamicMalloc::heap_listp=NULL;
  6. char * DynamicMalloc::mem_heap=NULL;
  7. char * DynamicMalloc::mem_brk=NULL;
  8. char * DynamicMalloc::mem_max_addr=NULL;
  9. DynamicMalloc::DynamicMalloc(){
  10. if(mem_heap==NULL){
  11. mem_errno=NoFault;
  12. mem_heap=(char*)malloc(WSIZE*MAX_HEAP*sizeof(char));
  13. if(mem_heap==NULL){
  14. mem_errno=OutofMemory;
  15. std::cout<<"overflow"<<std::endl;
  16. }
  17. mem_brk=mem_heap;
  18. mem_max_addr=mem_heap+WSIZE*MAX_HEAP*sizeof(char);
  19. mm_init();
  20. }
  21. }
  22. void * DynamicMalloc::mem_sbrk(unsigned int inc){
  23. if(inc<0||(mem_heap+inc>mem_max_addr)){
  24. mem_errno=OutofMemory;
  25. std::cout<<"memory overflow!"<<std::endl;
  26. return NULL ;
  27. }
  28. char *old_mem_brk=mem_brk;
  29. mem_brk+=inc+DSIZE; //预留空间,用于头和尾
  30. return (void*)old_mem_brk;
  31. }
  32. void DynamicMalloc::mm_init(){
  33. if((heap_listp=(char*)mem_sbrk(2*WSIZE))==NULL){
  34. return;
  35. }
  36. put_data(heap_listp,pack(0,ALLOCED));
  37. put_data(heap_listp+WSIZE,pack(0,ALLOCED));
  38. put_data(heap_listp+2*WSIZE,pack(0,ALLOCED));
  39. put_data(heap_listp+3*WSIZE,pack(0,ALLOCED));
  40. heap_listp+=2*WSIZE;
  41. extern_heap(CHUNKSIZE);
  42. }
  43. void* DynamicMalloc::extern_heap(unsigned int size){
  44. int words=(size%2)? (size+1)*WSIZE:(size)*WSIZE;
  45. char *bp=NULL;
  46. bp=(char*)mem_sbrk(words);
  47. put_data(mem_head(bp),pack(words,UNALLOCED)); //块头
  48. put_data(mem_ftrp(bp),pack(words,UNALLOCED)); //块脚
  49. put_data(mem_ftrp(bp)+WSIZE,pack(0,ALLOCED)); //新的“堆脚”,也是结束的标志
  50. coalesce(bp);
  51. return bp;
  52. }
  53. void DynamicMalloc::clearBlock(void *ptr){
  54. char *clear_ptr=(char*)ptr;
  55. for(int i=0;i<WSIZE; i++){
  56. *(clear_ptr+i)=0;
  57. }
  58. }
  59. void DynamicMalloc::coalesce(void *ptr){
  60. bool preAlloced=ALLOCED;
  61. bool nxtAlloced=ALLOCED;
  62. preAlloced=get_alloced(mem_head(pre_blkb(ptr))); //获得前一块的状态
  63. nxtAlloced=get_alloced(mem_head(next_blkb(ptr))); //获得下一块的状态
  64. if(preAlloced&&nxtAlloced){//前后两块都分配了
  65. return;
  66. }else if(preAlloced&&!nxtAlloced){//前一块己分配,后一块没有
  67. unsigned int new_size=get_size(mem_head(ptr))+get_size(mem_head(next_blkb(ptr)))+DSIZE;
  68. put_data(mem_head(ptr),pack(new_size,UNALLOCED));//设置新块头部
  69. put_data(mem_ftrp(ptr),pack(new_size,UNALLOCED)); //新块的脚
  70. //clearBlock(mem_ftrp(ptr));
  71. //clearBlock(mem_head(next_blkb(ptr))); //清理门户
  72. }else if(!preAlloced&&nxtAlloced){//前面的未分配,后面的分配了
  73. unsigned int new_size=get_size(mem_head(ptr))+get_size(mem_head(pre_blkb(ptr)))+DSIZE;
  74. put_data(mem_head(pre_blkb(ptr)),pack(new_size,UNALLOCED));
  75. put_data(mem_ftrp(ptr),pack(new_size,UNALLOCED));
  76. //clearBlock(mem_head(ptr));
  77. //clearBlock(mem_ftrp(pre_blkb(ptr)));
  78. }else if(!preAlloced&&!nxtAlloced){//前后都未分配
  79. unsigned int new_size=get_size(mem_head(ptr))+get_size(mem_head(pre_blkb(ptr)))+get_size(mem_head(next_blkb(ptr)));
  80. put_data(mem_head(pre_blkb(ptr)), pack(new_size,UNALLOCED));
  81. put_data(mem_ftrp(next_blkb(ptr)),pack(new_size,UNALLOCED));
  82. //clearBlock(mem_head(ptr));
  83. //clearBlock(mem_ftrp(ptr));
  84. //clearBlock(mem_ftrp(pre_blkb(ptr)));
  85. //clearBlock(mem_head(next_blkb(ptr))); //清理门户
  86. }
  87. }
  88. void* DynamicMalloc::mm_malloc(unsigned int size){
  89. unsigned int malloc_size=0;
  90. void *reptr=NULL;
  91. if(size==0){
  92. return NULL;
  93. }
  94. if(size<=DSIZE){
  95. malloc_size=DSIZE;
  96. }else{
  97. malloc_size=DSIZE*((size+DSIZE+DSIZE-1)/DSIZE);
  98. }
  99. if((reptr=find_fit(malloc_size))!=NULL){
  100. return (void*)reptr;
  101. }else{
  102. reptr=(void*)extern_heap(malloc_size);
  103. put_data(mem_head(reptr),pack(malloc_size,ALLOCED));
  104. put_data(mem_ftrp(reptr),pack(malloc_size,ALLOCED));
  105. return reptr;
  106. }
  107. }
  108. void* DynamicMalloc::find_fit(unsigned int size){
  109. char *ptr=next_blkb(heap_listp); //heap_listp一直指向序言块
  110. std::cout<<get_size(mem_head(ptr))<<std::endl;
  111. std::cout<<get_alloced(mem_head(ptr))<<std::endl;
  112. while(((get_size(mem_head(ptr))!=0)||(get_alloced(mem_head(ptr)))!=ALLOCED)){//从前往后 “首次匹配”
  113. std::cout<<get_size(mem_head(ptr))<<std::endl;
  114. std::cout<<get_alloced(mem_head(ptr))<<std::endl;
  115. if(((get_size(mem_head(ptr))>=size)&&(get_alloced(mem_head(ptr)))==UNALLOCED)){
  116. break;;
  117. }
  118. ptr=next_blkb(ptr);
  119. }
  120. if(get_alloced(mem_head(ptr))==ALLOCED&&get_size(mem_head(ptr))==0){//没有合适的空间
  121. mem_errno=NoRest;
  122. return NULL;
  123. }else{
  124. if(get_size(mem_head(ptr))>=size+MINCHUNK){
  125. unsigned int old_size=get_size(mem_head(ptr));
  126. put_data(mem_head(ptr),pack(size,ALLOCED)); //待分配块“头”
  127. put_data(mem_ftrp(ptr),pack(size,ALLOCED)); //待分配块“尾”
  128. put_data(mem_head(next_blkb(ptr)),pack(old_size-size-2*WSIZE,UNALLOCED));
  129. put_data(mem_ftrp(next_blkb(ptr)),pack(old_size-size-2*WSIZE,UNALLOCED));
  130. return ptr;
  131. }else{
  132. return ptr;
  133. }
  134. }
  135. }
  136. void DynamicMalloc::mm_free(void *ptr){
  137. put_data(mem_head(ptr),pack(get_size(mem_head(ptr)),UNALLOCED));
  138. put_data(mem_ftrp(ptr),pack(get_size(mem_head(ptr)),UNALLOCED));
  139. coalesce(ptr);
  140. }

测试


  1. #include "DynamicMalloc.h"
  2. #include<iostream>
  3. int main(){
  4. DynamicMalloc dynamicMalloc;
  5. char *ptr=(char*)dynamicMalloc.mm_malloc(10);
  6. for(int i=0;i<10;i++){
  7. *(ptr+i)=‘a‘;
  8. }
  9. for(int i=0;i<10;i++){
  10. std::cout<<*(ptr+i)<<std::endl;
  11. }
  12. char* p=(char*)dynamicMalloc.mm_malloc(20);
  13. for(int i=0;i<20;i++){
  14. *(p+i)=‘a‘;
  15. }
  16. for(int i=0;i<20;i++){
  17. std::cout<<*(p+i)<<std::endl;
  18. }
  19. char* pp=(char*)dynamicMalloc.mm_malloc(300);
  20. dynamicMalloc.mm_free(p);
  21. }

对于空相邻空闲块的管理策略:

也就是这部分的代码:

  1. void DynamicMalloc::coalesce(void *ptr){
  2. bool preAlloced=ALLOCED;
  3. bool nxtAlloced=ALLOCED;
  4. preAlloced=get_alloced(mem_head(pre_blkb(ptr))); //获得前一块的状态
  5. nxtAlloced=get_alloced(mem_head(next_blkb(ptr))); //获得下一块的状态
  6. if(preAlloced&&nxtAlloced){//前后两块都分配了
  7. return;
  8. }else if(preAlloced&&!nxtAlloced){//前一块己分配,后一块没有
  9. unsigned int new_size=get_size(mem_head(ptr))+get_size(mem_head(next_blkb(ptr)))+DSIZE;
  10. put_data(mem_head(ptr),pack(new_size,UNALLOCED));//设置新块头部
  11. put_data(mem_ftrp(ptr),pack(new_size,UNALLOCED)); //新块的脚
  12. //clearBlock(mem_ftrp(ptr));
  13. //clearBlock(mem_head(next_blkb(ptr))); //清理门户
  14. }else if(!preAlloced&&nxtAlloced){//前面的未分配,后面的分配了
  15. unsigned int new_size=get_size(mem_head(ptr))+get_size(mem_head(pre_blkb(ptr)))+DSIZE;
  16. put_data(mem_head(pre_blkb(ptr)),pack(new_size,UNALLOCED));
  17. put_data(mem_ftrp(ptr),pack(new_size,UNALLOCED));
  18. //clearBlock(mem_head(ptr));
  19. //clearBlock(mem_ftrp(pre_blkb(ptr)));
  20. }else if(!preAlloced&&!nxtAlloced){//前后都未分配
  21. unsigned int new_size=get_size(mem_head(ptr))+get_size(mem_head(pre_blkb(ptr)))+get_size(mem_head(next_blkb(ptr)));
  22. put_data(mem_head(pre_blkb(ptr)), pack(new_size,UNALLOCED));
  23. put_data(mem_ftrp(next_blkb(ptr)),pack(new_size,UNALLOCED));
  24. //clearBlock(mem_head(ptr));
  25. //clearBlock(mem_ftrp(ptr));
  26. //clearBlock(mem_ftrp(pre_blkb(ptr)));
  27. //clearBlock(mem_head(next_blkb(ptr))); //清理门户
  28. }
  29. }

这是开始的一些字段初使化:

  1.     static char* mem_heap; //指向堆首地址
  2. static char* mem_brk; //指向目前分配的“堆”的最后一个字的下一个
  3. static char* mem_max_addr; //一直指向最大所能分配的地址,“堆大小”
  4. static char* heap_listp; //一直指向序言块

来自为知笔记(Wiz)

时间: 2024-11-08 18:59:32

实现一个动态存储分配的相关文章

C/C++ 动态存储分配

C语言的动态分配函数: malloc(m):开辟m字节长度的地址空间,并返回这段空间的首地址 sizeof(x):计算变量x的长度 free(p):释放指针p所指变量的存储空间,即彻底删除一个变量 C++的动态存储分配: new  类型名T(初值列表) 功能:申请用于存放T类型对象的内存空间,并依初值列表赋以初值 结果值: 成功:T类型的指针,指向新分配的内存 失败:0(NULL) delete 指针P 功能:释放指针P所指向的内存.P必须是new操作的返回值

C语言动态存储分配

动态存储分配 C语言支持动态存储分配,即在程序执行期间分配内存单元的能力,利用动态存储分配,可以根据需要设计扩大(或缩小)的数据结构,虽然可以适用于所有类型的数据,但是动态存储分配更常用于字符串.数组和结构体 本文地址:http://www.cnblogs.com/archimedes/p/c-dynamic-storage-allocation.html,转载请注明源地址. 1.内存分配函数 3种内存分配函数都是声明在<stdlib.h>中: malloc函数--分配内存块,但是不对内存块进

串的动态存储分配

串:由零个或者多个字符组成的有限序列.零个字符的串称为空串,和空格串[一个或多个空格诸城的串]有区别,请注意比较.在串的抽象数据类型中,有五个操作组成最小操作子集,分别是串赋值StrAssign,串比较StrCompare,求串长StrLength ,串联接Concat,求子串SubString.现以串的动态存储结构为例,将5个基本操作实现如下: 具体介绍详见注释. 1 /** 2 在串的抽象数据类型的13中操作中:串赋值StrAssign,串比较StrCompare,求串长StrLength

指针和动态存储分配

1 指针 指针是C语言的基本概念,每种数据类型都有相应的指针类型.指针类型变量存放的值实际上就是内存地址.指针的最基本操作: & 取地址 * 去引用(间接引用) 如: int i, *pi              //其中 i 是整型变量,pi 是指向整数的指针. pi = &i ;             //则 &i 返回i的地址并把它赋值给 pi ,若要给 i 赋值,可以写成 i = 10 ; 或者 *pi = 10 ; pi 之前的 * 是去引用 , 10 并未存放指针里

【Cpp】考点·堆栈&amp;动态内存分配

动态内存分配 堆内存分配与释放 C/C++定义了四个内存区间:代码区,全局变量与静态变量区,局部变量区(栈区),动态内存区(堆区) 通常定义变量(或对象),编译器在编译时都可以根据该变量(或对象)的类型知道所需内存空间的大小,从而系统在适当的时候为他们分配确定的存储空间.这种内存分配称为静态存储分配.有些操作对象只在程序运行时才确定,这样编译时无法为他们预定存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配,这种方法称为动态存储分配.所有动态存储分配都在堆区中进行. 当程序运行到需要一

C++ 动态内存分配(6种情况,好几个例子)

1.堆内存分配 : C/C++定义了4个内存区间: 代码区,全局变量与静态变量区,局部变量区即栈区,动态存储区,即堆(heap)区或自由存储区(free store). 堆的概念: 通常定义变量(或对象),编译器在编译时都可以根据该变量(或对象)的类型知道所需内存空间的大小,从而系统在适当的时候为他们分配确定的存储空间.这种内存分配称为静态存储分配: 有些操作对象只在程序运行时才能确定,这样编译时就无法为他们预定存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配,这种方法称为动态存储分

c++动态内存分配 浅析

用new 运算符实现动态内存分配 P = new T; T是任意类型名,P是类型为T * 的指针. 动态分配出一片大小为 sizeof(T)字节的内存空间,并且将该 内存空间的起始地址赋值给P. P = new T[N]; T :任意类型名 P :类型为T * 的指针 N :要分配的数组元素的个数,可以是整型表达式 动态分配出一片大小为 sizeof(T)字节的内存空间,并且 将该内存空间的起始地址赋值给P. int * pn; 2.int i = 5; 3.pn = new int[i * 2

Java中数据存储分配

(1)内存分配的策略 按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的. 静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编 译时就可以给他们分配固定的内存空间.这种分配策略要求程序代码中不允许有可变数据结构(比如可变数组)的存在,也不允许有嵌套或者递归的结构出现,因为 它们都会导致编译程序无法计算准确的存储空间需求. 栈式存储分配也可称为动态存储分配,是由一个类似于堆栈的运行栈来实现的.和静态存 储分配相反,在栈式存储方案中,程序对

动态内存分配类实现

今天学习了C++语言的内存动态分配,并借助所学的知识实现了一个动态内存分配类. 问题的背景为:在已经实现了一个点类的基础上,实现一个动态内存分配类,这个类 的功能为:实现根据输入的数目size,动态的生成size个点类对象:并在提供一个借口 可以对pos位置的对象进行操作:在对象生存期结束时,可以自动释放分配的内存空间. 根据描述的问题描述的需求,规划了如下的类图: 写出了一个包含三个方法的对点动态分配内存的类: 1: #ifndef _ARRAYOFPOINTS_H 2: #define _A