STL源码:alloc分配器

        记录一下自己对于分配器的学习笔记以及代码。和测试用例;

        这个是在学习《STL源码刨析》书籍后,写的数据结构和函数;   

 内存池代码实现:

// alloc.h
#ifndef ALLOC_H
#define ALLOC_H
#include<iostream>
#include <cstddef>
#include <cstdio>

namespace mystl {
   
   // static是在这个作用域中,使用了static就会使得不会在局部使用后被析构了,生命周期变长。别的作用域看不见; 
   //而静态局部变量不能被extern
   
   // 所以使用static进行成员函数的修饰时候,此函数并不属于任何一个对象,而是属于这个类; 
   // static的数据成员要在类外(无论什么修饰)进行初始化,但是private的成员要在类内进行,或者构造函数处; 
   int ALIGN = 8;
   union Free_List {
      Free_List* free_link;   // 是指向下一个待分配空间的指针 
      char data[1];             // 其实好像没啥用 
   };
//   int ALIGN = 8;
   class alloc{
   // 访问类中成员权限的限制符,其实针对的是继承,以及内外的试用权限;
   private:
      static size_t upbound(size_t n);    // 将n变为8的倍数
      static void* refill(size_t n);      // 如果哪个链上没空间了,就去补充 
      static void* pool_alloc(size_t n, size_t& alloc_num);         // 在内存池中找n大小的内存空间 
   private:
         static Free_List* free_list[16];   // 8、16、24......128  free_list链表 
         static char* start_free;   // 内存池的首地址
         static char* end_free;     // 内存池的尾地址 
         static size_t heap_size;   // 如果频繁的要内存,heap_size就会增大,内存池就会向heap要更多的内存
   
   public: 
         static void* allocate(int n);  // 客户端问自由链表要n bit的大小空间;
         static void dealloc(void* p, size_t n);        // 释放 p 指向的大小为 n 的空间, p 不能为 0 
         static void* realloc(void* p, size_t old_size, size_t new_size);  // 将旧的空间进行客户端的释放,将新的地址给客户端进行分配
         
   };
   // 因为静态成员属于整个类,而不属于某个对象,如果在类内初始化,会导致每个对象都包含该静态成员,这是矛盾的。
   // 类外定义和初始化是保证static成员变量只被定义一次的好方法
   Free_List* alloc::free_list[16] = {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,
   nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr};   // 类外对静态成员变量进行初始化
   
   char* alloc::start_free = nullptr;
   char* alloc::end_free = nullptr;
   size_t alloc::heap_size = 0;
   
   // 进行空间分配 
   void* alloc::allocate(int n) {
      std::cout << "您需要的空间:" << n << std::endl;
      std::cout << "开始分配空间" << std::endl;
      if (n > 128)   // 大于128 B时候 
      {
         void* result = malloc(n);
         std::cout << "系统直接分配空间!" << std::endl;
         return result;
      }   
      size_t num_bit = upbound(n); // 进行多大空间的计算
      std::cout << "开始计算空间大小" << num_bit << std::endl;
      int node_num = num_bit / ALIGN - 1;
      std::cout << "插入的自由链表下标为:" << node_num << std::endl;
      Free_List* result = free_list[node_num]; // 里面存的是指向空闲空间的指针    
      if (free_list[node_num] == nullptr)
      {
         std::cout << node_num <<"号节点,此刻为空!" << std::endl;
         void* result = refill(num_bit);
         std::cout << "重新填充完毕,分配空间结束!" << std::endl;
         return result;
      }
      free_list[node_num] = result->free_link;
      std::cout << "自由链表有空间,链表分配空间结束!" << std::endl;
      return result;
   }
    
   void alloc::dealloc(void* p, size_t n)   // 将 p指向的空间进行释放 
   {
      if (n > 128)
      {
         std::free(p); 
         return; 
      }  
      p = (Free_List*)p;
      int index = upbound(n) / ALIGN;   // 找到index 
      Free_List* myfree_list = free_list[index]; 
//      myfree_list->free_link = p->free_link;
      std::free(p);
   }
   
   // 进行空间的重新分配 
   void* alloc::realloc(void* p, size_t old_size, size_t new_size)
   {
      // 释放旧的空间 
      void* result;
      if (old_size > 128)
         std::free(p); 
      else {
         size_t index = upbound(old_size) / ALIGN;
//         free_list[index] = (Free_List*)p->free_link;
         std::free(p);
      }
      
      // 分配新的空间 
      if (new_size > 128) { 
         void* result = malloc(new_size);
      }
      else {
         void* result = allocate(new_size);
      }
      return result;     
   }
   
   /*
   调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块。
   然后,将该内存块一分为二(一块的大小与用户请求的大小相等,另一块的大小就是剩下的字节)。
   接下来,将分配给用户的那块内存传给用户,并将剩下的那块(如果有的话)返回到连接表上。 
  调用free函数时,它将用户释放的内存块连接到空闲链上。到最后,空闲链会被切成很多的小内存片段,
   如果这时用户申请一个大的内存片段,那么空闲链上可能没有可以满足用户要求的片段了。
   于是,malloc函数请求延时,并开始在空闲链上翻箱倒柜地检查各内存片段,对它们进行整理,
   将相邻的小空闲块合并成较大的内存块。 
   
   通常意义上我们malloc(n * sizeof(char) 其实就是动态分配n个B     1Byte=8bit 
   */
   
   // 进行空间大小的8倍镜 
   size_t alloc::upbound(size_t n){
        return ((n + ALIGN - 1) & ~(ALIGN - 1));
   }
   
   void* alloc::refill(size_t n) {
      // pool_alloc()
      std::cout << "开始填充链表!" << std::endl; 
      size_t alloc_num = 20;   // 一次性分配20个大小空间 
      size_t bytes = upbound(n);
//    size_t index = n / __ALIGN - 1; 
      char* chunk = (char*)pool_alloc(bytes, alloc_num);   // 从内存池中找空间
      if (alloc_num == 1)
      {
         std::cout << "会从这里返回吗?"<< std::endl; 
         return chunk;
         
      }
      std::cout << "从内存池拿到的内存大小为:" << alloc_num << std::endl; 
      Free_List* result;
      Free_List* cur; 
//      Free_List* next = (Free_List*) (chunk + bytes);   // 就是下一个要给链表的节点 
      result = (Free_List*) chunk;   // 返回客户端一个,剩下的自己用 
      Free_List* myfree_list = free_list[upbound(n) / ALIGN - 1];
      Free_List* next = (Free_List*)(chunk + bytes);
      myfree_list = next;
      cur = myfree_list;
//      myfree_list = cur;   // 指向下一个节点 
      std::cout << "开始自由链表的串联!" << std::endl; 
      for (int i = 1; ; i++) { 
         cur = next;
         next = (Free_List*) ((char*) next + bytes);
         if (alloc_num - 1 == i)
         {
            cur->free_link = 0;
            break;
         }
         else 
            cur->free_link = next; 
      }
      std::cout << "链表填充完毕!" << std::endl;
      return result;
   } 
   
   void* alloc::pool_alloc(size_t n,size_t& alloc_num) {
      std::cout << "开始填充内存池" << std::endl;
      void* result;
      size_t total_get = n * alloc_num;
      size_t total_mem = end_free - start_free;
      if (total_get <= total_mem) {
         result = start_free;
         start_free = start_free + total_get;
//       return result;
      }
      else if (total_mem > n){
      // 内存池空间不足了 
         alloc_num = total_mem / n;  // 最多分配的个数
         total_get = alloc_num * n;  // 最多分配的空间
         result = start_free;
         start_free = start_free + total_get;
      }
      else {   // 也就是说一个空间都给不了了
         size_t bytes_get = 2 * total_get;
         start_free = (char*) malloc(bytes_get);  // 分配双倍的空间 
         end_free = start_free + bytes_get;
         result = start_free;
         start_free = start_free + total_get;
//       return result;
      }    
   std::cout<< "内存池填充完毕!" << std::endl; 
   return result;
   
   } 

} 



#endif

 测试用例的实现:

#include<iostream>
#include"alloc.h"
using namespace std;
using namespace mystl;

void test_alloc();
int main() {
   // test_alloc();  alloc分配器勉强通过测试 
   return 0;
} 


void test_alloc() {
   cout << "***开始测试alloc分配器啦***" << endl;
   alloc a;
   void* client = a.allocate(45);
   free(client);  // 重新分配空间没问题 
}

代码实现结果(只测试分配12、45、129时候的结果)

需要内存大小为45时候,alloc的结果;

 需要内存大小为12时候,alloc的结果;

  需要内存大小为129时候,alloc的结果;

        由于自由链表下面挂着有空间时候,我们刚好需要此index下空间,难以测试,也懒得测,就不会进行测试了,感觉逻辑应该问题不大,大差不差的。 over,记录在此!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值