最开始的时候看到了许式伟的内存管理变革系列,看到性能测试结果的时候,觉得这个实现很不错,没有深入研究其实现。现在想把这个用到自己的一个项目中来,在linux下编译存在一些问题,所以打算深入研究一下。

讨论C++内存管理的有两个主要的博客,一个是许式伟的系列,(CSDN: http://blog.csdn.net/xushiweizh/article/details/1388982,许式伟个人空间:http://xushiwei.com/gc-allocator-summary);另一个是CppExplore的一个内存管理系列(http://www.cppblog.com/CppExplore/archive/2008/02/18/42890.html). 主要来研究许式伟的内存管理。

学习许式伟的内存管理器实现,参考
http://cplusplus.wikidot.com/cn:memory-management-innovation

gc_1
   simple_gc.h
   test.cpp
实现了系列第一篇文章中讲到的内容,一个基本的Allocator,对malloc的封装,用于申请内存,利用new可以在指定位置申请内存,实现新的new函数,在allocator申请的内存上分配内存。
如果所有的内存都是从某个allocator申请的,那么释放allocator的内存,就释放掉了之前所有在它上面分配的内存。但这个simple_gc只是概念上的,没有实现memory pool的管理。所以接下来看AutoAlloc.

gc_2
    auto_alloc.h
    auto_alloc.cpp
    test.cpp
实现了系列第二篇文章中讲到的内容,一个包含memory block管理的Allocator,被其称之为最袖珍的垃圾回收器--AutoAlloc.由于他写文章之后又对代码有部分修改,但又没有修改完全,文章中的代码片段需要进行修正和补充,才能进行编译。每个memory block大小为2048字节,对于小于这个大小的对象,可以直接从这个block里面分一部分,如果剩余部分还足够大,可以给新的对象,那么就继续分。如果无法满足要求,则申请新的block,或者更大的block。所以有些block没有被完全利用,产生一些碎片。由于申请的一块可以给很多对象使用,不需要每个对象申请一次,所以申请内存的效率比较高。但是这个内部需要维护memory block的链表,析构函数的链表,及碎片的存在,会有一些浪费。

gc_1和gc_2的代码,

// simple_gc.h
#ifndef SIMPLE_ALLOC_H_
#define SIMPLE_ALLOC_H_ #include <cstdlib> /* malloc, free, rand */
#include <new> template <class Type>
struct DestructorTraits
{
static void Destruct(void* pThis)
{
((Type*)pThis)->~Type();
}
}; typedef void (*FnDestructor)(void* pThis); class SimpleAlloc
{
public:
//注意这里提供的参数fnDestroy,它是为那些具备垃圾回收能力的allocator需要提供。
void* Alloc(size_t cb, FnDestructor fnDestroy = NULL)
{
return malloc(cb);
} //注意这里有看似多余的参数cb,这完全是为了和后续提供的allocator规格一致的需要。
void Free(void* data, size_t cb)
{
free(data);
}
}; // 类似于new Type
template <class Type, class AllocType>
inline Type* New(AllocType& alloc)
{
void* obj = alloc.Alloc(sizeof(Type), DestructorTraits<Type>::Destruct);
return new(obj) Type;
} // 类似于new Type(arg1)
template <class Type, class ArgType1, class AllocType>
Type* New(ArgType1 arg1, AllocType& alloc)
{
void* obj = alloc.Alloc(sizeof(Type), DestructorTraits<Type>::Destruct);
return new(obj) Type(arg1);
} // 类似于new Type[count]
template <class Type, class AllocType>
Type* NewArray(size_t count, AllocType& alloc)
{
void* obj = alloc.Alloc(sizeof(Type)*count, DestructorTraits<Type>::Destruct);
return new(obj) Type[count];
} #endif /* SIMPLE_ALLOC_H_ */

auto_alloc.h和auto_alloc.cpp

#ifndef AUTO_ALLOC_H_
#define AUTO_ALLOC_H_ #include <cstdlib> /* malloc, free, rand */
#include <new> typedef void (*FnDestructor)(void* pThis); /*
class AutoAlloc
{
public:
~AutoAlloc(); // 析构函数。自动调用Clear释放内存
void* allocate(size_t cb); // 类似于malloc(cb)
void* allocate(size_t cb, FnDestructor fn); // 申请内存并指定析构函数
void clear(); // 析构并释放所有分配的对象
};
*/ class AutoAlloc
{
public:
enum { BlockSize = };
private:
struct _MemBlock
{
_MemBlock* pPrev;
char buffer[BlockSize];
};
enum { HeaderSize = sizeof(_MemBlock) - BlockSize }; char* m_begin;
char* m_end; _MemBlock* _ChainHeader() const
{
return (_MemBlock*)(m_begin - HeaderSize);
} struct _DestroyNode
{
_DestroyNode* pPrev;
FnDestructor fnDestroy;
};
_DestroyNode* m_destroyChain; public:
AutoAlloc();
~AutoAlloc(); // 析构函数。自动调用Clear释放内存
void* Alloc(size_t cb); // 类似于malloc(cb)
void* Alloc(size_t cb, FnDestructor fn); // 申请内存并指定析构函数
void Clear(); // 析构并释放所有分配的对象 }; template <class Type>
struct DestructorTraits
{
static void Destruct(void* pThis)
{
((Type*)pThis)->~Type();
}
}; // 类似于new Type
template <class Type, class AllocType>
inline Type* New(AllocType& alloc)
{
void* obj = alloc.Alloc(sizeof(Type), DestructorTraits<Type>::Destruct);
return new(obj) Type;
} // 类似于new Type(arg1)
template <class Type, class ArgType1, class AllocType>
Type* New(ArgType1 arg1, AllocType& alloc)
{
void* obj = alloc.Alloc(sizeof(Type), DestructorTraits<Type>::Destruct);
return new(obj) Type(arg1);
} // 类似于new Type[count]
template <class Type, class AllocType>
Type* NewArray(size_t count, AllocType& alloc)
{
void* obj = alloc.Alloc(sizeof(Type)*count, DestructorTraits<Type>::Destruct);
return new(obj) Type[count];
} #endif /* AUTO_ALLOC_H_ */
#include "auto_alloc.h"

#include <cstdio>

AutoAlloc::AutoAlloc()
{
m_begin = m_end = (char*)HeaderSize;
m_destroyChain = NULL;
} void* AutoAlloc::Alloc(size_t cb)
{
if(m_end - m_begin < cb)
{
if (cb >= BlockSize)
{
_MemBlock* pHeader = _ChainHeader();
_MemBlock* pNew = (_MemBlock*)malloc(HeaderSize + cb);
if (pHeader)
{
pNew->pPrev = pHeader->pPrev;
pHeader->pPrev = pNew;
}
else
{
m_end = m_begin = pNew->buffer;
pNew->pPrev = NULL;
}
return pNew->buffer;
}
else
{
_MemBlock* pNew = (_MemBlock*)malloc(sizeof(_MemBlock));
pNew->pPrev = _ChainHeader();
m_begin = pNew->buffer;
m_end = m_begin + BlockSize;
}
}
return m_end -= cb;
} void AutoAlloc::Clear()
{ // destroy
printf("destroy\n");
while (m_destroyChain)
{
m_destroyChain->fnDestroy(m_destroyChain + );
m_destroyChain = m_destroyChain->pPrev;
} // free memory
printf("free memory\n");
_MemBlock* pHeader = _ChainHeader();
while (pHeader)
{
_MemBlock* pTemp = pHeader->pPrev;
free(pHeader);
pHeader = pTemp;
}
m_begin = m_end = (char*)HeaderSize;
} void* AutoAlloc::Alloc(size_t cb, FnDestructor fn)
{
_DestroyNode* pNode = (_DestroyNode*)Alloc(sizeof(_DestroyNode) + cb);
pNode->fnDestroy = fn;
pNode->pPrev = m_destroyChain;
m_destroyChain = pNode;
return pNode + ;
} AutoAlloc::~AutoAlloc()
{
Clear();
}

测试代码这里给出一份就可以了,

//#include "simple_gc.h"
#include "auto_alloc.h" #include <cstdio> class MyClass
{
public:
int a;
public:
MyClass(int t=):a(t){}
~MyClass(){}
void Print()
{
printf("%d\n",a);
}
}; int main()
{ // SimpleAlloc alloc;
AutoAlloc alloc;
int count = ; int* intArray = NewArray<int>(count, alloc); for(int i=;i<count;i++)
{
intArray[i] = i+;
}
for(int i=;i<count;i++)
{
printf("%d ",intArray[i]);
}
printf("\n"); MyClass* obj = New<MyClass>(alloc); obj->Print(); int arg1 = ;
MyClass* objWithArg = New<MyClass>(arg1, alloc); objWithArg->Print(); alloc.Clear(); // MyClass* objArray = NewArray<MyClass>(count, alloc); return ;
}

gc_3
这里只是介绍了AutoFreeAlloc的适用情况。AutoFreeAlloc的内存是在最后一次性释放的。在有些情况中,有些对象已经不需要,
需要手动释放,避免大量内存被占用,这个时候AutoFreeAlloc就不适合了。

gc_4
这里介绍boost::object_pool. boost::object_pool管理某一类对象,支持手动释放内存,对于没有手动释放的内存,这个object_pool会遍历
所有的block,确定是否已经是自由内存,如果不是,则进行回收。
allocator只是内存管理器,而 gc allocator则是指具有垃圾回收功能的内存管理器。

gc_5
这里评论了智能指针和其它垃圾回收器的使用情况。

gc_6
这里介绍了ScopeAlloc,给出了很多代码片段,不容易组织称完整的代码。但可以大致了解ScopeAlloc的原理。
在AutoFreeAlloc中,内置了一个memory block的链表,来管理内存。而在ScopeAlloc中,向BlockPool申请内存。
相比于AutoFreeAlloc,适用范围更广,速度更快。

gc_7
将ScopeAlloc用于STL时,需要将ScopeAlloc封装一层,得到StlAlloc.

gc_8
这里介绍了多线程环境中的gc allocator。推荐的方式是,每个线程有自己的allocator,但是都向同一个memory pool申请内存。
这里要求memory pool是多线程安全的,互斥申请内存。

虽然他的代码可以下载,但我在linux使用的时候出现各种问题,由于他包含了多线程模型的支持,代码也复杂了一些,需要继续研究。

代码可以在linux下编译,在boost-memory-xx/libs/memory/build/下面有Makefile文件,Makefile.li32表示linux 32bit版本的makefile.

在编译之前还是需要做几个小的修改,一个是关于memcpy,在basic.hpp里面添加#include <cstring>,另一个是_alloca函数,添加#include <cstdlib>。

然后编译得到的为动态库文件,libboost-memory.so,在build/Debug下面。

C++中的垃圾回收和内存管理的更多相关文章

  1. Java中的垃圾回收机制&内存管理&内存泄漏

    1. Java在创建对象时,会自动分配内存,并当该对象引用不存在的时候,释放这块内存. 为什么呢? 因为Java中使用被称为垃圾收集器的技术来监视Java程序的运行,当对象不再使用时,就自动释放对象所 ...

  2. C++中的垃圾回收和内存管理(续)

    boost memory的gc_allocator的使用 首先编译生成boost-memory的库,由于生成的是.so的动态库,所以需要在运行程序之前,将库文件的路径添加到LD_LIBRARY_PAT ...

  3. 深入了解C#系列:谈谈C#中垃圾回收与内存管理机制

    今天抽空来讨论一下.Net的垃圾回收与内存管理机制,也算是完成上个<WCF分布式开发必备知识>系列后的一次休息吧.以前被别人面试的时候问过我GC工作原理的问题,我现在面试新人的时候偶尔也会 ...

  4. C#中垃圾回收与内存管理机制

    今天抽空来讨论一下.Net的垃圾回收与内存管理机制,也算是完成上个<WCF分布式开发必备知识>系列后的一次休息吧.以前被别人面试的时候问过我GC工作原理的问题,我现在面试新人的时候偶尔也会 ...

  5. 【java虚拟机序列】java中的垃圾回收与内存分配策略

    在[java虚拟机系列]java虚拟机系列之JVM总述中我们已经详细讲解过java中的内存模型,了解了关于JVM中内存管理的基本知识,接下来本博客将带领大家了解java中的垃圾回收与内存分配策略. 垃 ...

  6. 深入理解Node.js中的垃圾回收和内存泄漏的捕获

    深入理解Node.js中的垃圾回收和内存泄漏的捕获 文章来自:http://wwsun.github.io/posts/understanding-nodejs-gc.html Jan 5, 2016 ...

  7. 《JavaScript 闯关记》之垃圾回收和内存管理

    JavaScript 具有自动垃圾收集机制(GC:Garbage Collecation),也就是说,执行环境会负责管理代码执行过程中使用的内存.而在 C 和 C++ 之类的语言中,开发人员的一项基本 ...

  8. JavaScript 之垃圾回收和内存管理

    JavaScript 具有自动垃圾收集机制(GC:Garbage Collecation),也就是说,执行环境会负责管理代码执行过程中使用的内存.而在 C 和 C++ 之类的语言中,开发人员的一项基本 ...

  9. JavaScript中的垃圾回收和内存泄漏

    摘要: JS内存管理. 作者:浪里行舟 Fundebug经授权转载,版权归原作者所有. 前言 程序的运行需要内存.只要程序提出要求,操作系统或者运行时就必须供给内存.所谓的内存泄漏简单来说是不再用到的 ...

随机推荐

  1. Dubbo原理及配置

    技术交流群:233513714 Dubbo的背景 随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进 ...

  2. DecimalFormat的用法

    DecimalFormat 是 NumberFormat 的一个具体子类,用于格式化十进制数字. DecimalFormat 包含一个模式 和一组符符号含义:  0 一个数字 # 一个数字,不包括 0 ...

  3. **leetcode笔记--4 Sum of Two Integers

    question: Calculate the sum of two integers a and b, but you are not allowed to use the operator + a ...

  4. Windows扩展屏开发总结

    本文来自网易云社区 作者:梁敏 一.多屏设置 在设置-系统-可以点击显示器1和2,可以进行单独设置: "使之成为我的主显示器"可以设置当前显示器是主屏:主屏的选择会决定整个虚拟屏幕 ...

  5. ubuntu 14.04安装nginx+php

    转自:http://www.cnblogs.com/helinfeng/p/4219051.html 基于最新的Ubuntu 14.04(2014年9月)搭建nginx.php.mysql环境,以下全 ...

  6. Qt QLabel 播放GIF动画

    很久以前用过,不过慢慢的不用了,就慢慢的忘记了,今天拾起来,记录一下,以后用的时候可以翻一下 QLabel播放GIF动画其实很简单 第一步,需要包含头文件,Qt播放GIF动画,我使用的是QMovie类 ...

  7. Ajax请求被缓存的几种处理方式

    Ajax请求被缓存的几种处理方式 我们都知道IE会针对ajax请求的地址缓存请求结果,直到缓存过期之前,针对相同地址发出的请求,只有第一次会请求会真正发送到服务端.在某种情况下,这种缓存机制确实能提高 ...

  8. Word2Vec词向量(一)

    一.词向量基础(一)来源背景  word2vec是google在2013年推出的一个NLP工具,它的特点是将所有的词向量化,这样词与词之间就可以定量的去度量他们之间的关系,挖掘词之间的联系.虽然源码是 ...

  9. LeetCode 2——两数相加

    1. 题目 2. 解答 循环遍历两个链表 若两个链表都非空,将两个链表结点的值和进位相加求出和以及新的进位 若其中一个链表为空,则将另一个链表结点的值和进位相加求出和以及新的进位 然后将每一位的和添加 ...

  10. 阿里云服务器安装https证书 centos + httpd + Symantec

    一. 环境 centos7 阿里云服务器, httpd服务, 阿里云免费的Symantec证书 阿里云Symantec 有个免费版的证书, 具体怎么申请可以去百度解决 二. 网上大部分的经验贴都是要A ...