• 实现一个动态存储分配


    如何自己实现一个动态存储的分配机制,当然有很多的存储的分配方法,关键在于“堆”的管理。
    这里我们使用“隐式链表”的方法实现对“堆”的分配。
    而且分配的单位是“字”,这里的字是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; //一直指向序言块












  • 相关阅读:
    计算机网络——浅析TCP粘包,拆包发生的原因以及解决方式
    计算机网络——谈谈HTTP中GET与POST的区别
    浅析Cookie、Session以及Token机制
    说说红黑树——不谈操作,只讲理解
    设计模式(1)——单例模式详解
    【转载】二叉排序树和平衡二叉树详解
    深入理解Java中方法重载的实现原理
    真win10官方原版ISO下载方法
    我的Windows装机必备软件与生产力工具
    Caffe源码理解3:Layer基类与template method设计模式
  • 原文地址:https://www.cnblogs.com/yml435/p/4690933.html
Copyright © 2020-2023  润新知