从STL标准库ALLOC中学习内存管理

从STL标准库ALLOC中学习内存管理

STL学习的第一个话题就是内存分配,也是各类容器和算法的基础。每一个容器均配有一个内存分配器用于管理内存。一般情况下,我们没有必要去实现一个内存分配器,编译器会默认给配置一个功能很强大的内存管理器,也是我们学习的重点。默认的内存管理器有以下特点:

1、对大块内存和小块内存的申请,分别进行处理;例如大于128byte的调用malloc直接分配。小于128byte的维护一个内存池进行动态分配。

2、对小块内存的管理通过维护字节为8、16、24、32等不同长度的单链表进行动态的分配与回收,进一步提高效率并且减少内存片。

3、采用union结构产生单链表,减少next_ptr带来的额外内存消耗

模拟STL中对小块内存的管理,实现了一个对内存管理的程序,详细解释如下:

头文件:

// Created/Modified Time: Sat 13 Jul 2013 09:54:06 PM CST
// File Name: test_alloc.h
// Description:
#ifndef HOME_FANGQINGAN_FQA_PROGRAM_TEST_ALLOC_H_
#define HOME_FANGQINGAN_FQA_PROGRAM_TEST_ALLOC_H_
namespace test {
// 最小内存管理单位
const int kMinAlign = 8; // min alloc mem
const int kMaxAlign = 128;  // 最大内存管理单位
const int kNFreeList = kMaxAlign / kMinAlign;  // 需要维护的单链表的个数
const int kMinChunk = 20;  // 内存扩充时最小倍数
union obj {
  union obj* free_list_link;  // 内部使用free_list_link进行单链表的串接
  char clint_data[1];  // 给用户的数据
};
class MyAlloc {
 public:
  // 内存管理的两个函数,申请和释放
  static void *allocate(size_t n);
  static void deallocate(void *p, size_t n);
 private:
  static void *refill(size_t n);
  static char* chunk_alloc(size_t size, int& nobjs);
  // main vars
  static obj* free_list[kNFreeList];  // 单链表数组
  static char* start_free;//内存池开始位置 
  static char * end_free;//内存池结束位置
  static size_t heap_size;//已经分配内存大小
};
}

#endif // HOME_FANGQINGAN_FQA_PROGRAM_TEST_ALLOC_H_
源文件:

// Created/Modified Time: Sat 13 Jul 2013 10:04:22 PM CST
// File Name: test_alloc.cc
// Description:

#include "test_alloc.h"

namespace test {
// static vars
obj*MyAlloc::free_list[kNFreeList] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
char *MyAlloc::start_free = 0;
char* MyAlloc::end_free = 0;
size_t MyAlloc::heap_size = 0;
// 申请申请内存大小,确定使用哪个链表结构
size_t free_list_index(size_t bytes) {
  return (bytes + kMinAlign-1)/kMinAlign-1;
}
// 对于不足8字节的 进行提升
size_t round_up(size_t bytes) {
  return (bytes + kMinAlign - 1) & ~(kMinAlign-1);
}

// 分配内存
void* MyAlloc::allocate(size_t n) {
  if (n>kMaxAlign) {  // no deal
    return 0;
  }
  obj** my_free_list = free_list + free_list_index(n);
  obj* result = *my_free_list;
  if(result == 0) {
    // 如果某链表为空,则从内存池中分配一些到该链表
    void *r = refill(round_up(n));
    return r;
  }
  *my_free_list = result->free_list_link;
  return result;
}
void MyAlloc::deallocate(void *p, size_t n) {
  if (n > kMaxAlign)
    return;
  obj** my_free_list = free_list + free_list_index(n);
  obj* q = (obj*)p;
  q->free_list_link = my_free_list;
  *my_free_list = q;
}
// 用于填充空的链表结构
void *MyAlloc::refill(size_t n) {
  int nobjs = kMinChunks;
  // 从内存池中申请内存,nobjs为引用类型,返回能够申请到的内存块个数
  char * chunk = chunk_alloc(n, nobjs);
  obj** my_free_list;
  obj* current_obj, *next_obj;
  if(nobjs == 1)
    return chunk;
  my_free_list = free_list + free_list_index(n);
  obj* result = (obj*)chunk;
  *my_free_list = next_obj = (obj*)(chunk + n);
  // 将多余的内存块插入到链表中,等同于单链表的标头插入
  for (int i = 1;;i++) {
    current_obj = next_obj;
    next_obj = (obj*)((char*)next + n);
    if (nobjs - 1 == i) {
      current_obj->free_list_link = 0;
      break;
    } else {
      current_obj->free_list_link = next_obj;
    }
  }
  return result;
}
// 申请nobjs块空间,如果不够则从系统内存中获取
char *MyAlloc::chunk_alloc(size_t size, int& nobjs) {
  char *result;
  size_t total_bytes = size* nobjs;
  size_t left_bytes = end_free - start_free;
  if (left_bytes >= total_bytes) {
    result = start_free;
    start_free += total_bytes;
    return result;
  }
  // 有多少分配多少
  if (left_bytes >= size) {
    nobjs = left_bytes / size;
    total_bytes = size * nobjs;
    result = start_free;
    start_free += total_bytes;
    return result;
  }
  // 每次从系统申请空间时,多申请一些,至少为需求的两倍。
  size_t bytes_to_get = 2* total_bytes + round_up(heap_size) >> 4;
  if (left_bytes > 0) {
    obj**my_free_list = free_list + free_list_index(left_bytes);
    (obj*)start_free->free_list_link = *my_free_list;
    *my_free_list = (obj*)start_free;
  }
  start_free = (char *)malloc(bytes_to_get);
  if (start_free == 0) {
    nobjs = 0;
    return 0;
  }
  end_free = start_free = bytes_to_get;
  heap_size += bytes_to_get;
  chunk_alloc(size, nobjs);
}
}

总结

对内存池管理的目的减少大量申请和释放空间给程序带来时间开销,同时也能够减少内存碎片。实际应用中可以直接通过对象池的方法,对实际对象进行管理。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++ STL标准模板)是C++标准的一部分,提供了一组通用的数据结构和算法。STL标准文文档涵盖了STL的各个部分,包括容器(container)、迭代器(iterator)、算法(algorithm)等。 STL文文档可以帮助开发者更好地理解和使用STL,具体内容包括: 1. 容器:STL提供了多种容器类型,如vector、list、map等,这些容器提供了不同的数据存储和操作方式。文档会介绍每种容器的特点、用法和示例代码。 2. 迭代器:迭代器是与容器配合使用的一种机制,通过迭代器可以访问和遍历容器的元素。文档会介绍迭代器的种类、使用方法以及常见操作。 3. 算法:STL提供了众多的算法,如排序、查找、复制等,可以在不同的容器上进行操作。文档会详细介绍每个算法的功能、参数和使用示例。 4. 函数对象:STL提供了函数对象机制,可以将函数或函数对象作为算法的参数,用于执行特定的操作。文档会介绍函数对象的定义和使用方式。 STL标准文文档的作用主要有两个方面:一是帮助新手学习和理解STL的使用方法,提供了丰富的示例和解释;二是方便开发者在实际项目使用STL,对于算法和容器的选择和使用提供了参考和指导。 总之,STL标准文文档是一份重要的资料,对于学习和使用C++的开发者来说都具有很大的价值。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值