快捷搜索:

C++内存管理变革(3):另类内存管理

最简单的C++/Java法度榜样

最简单的Java法度榜样:

class Program

{

public static void main()

{

new int;

}

}

对应的C++法度榜样:

void main()

{

new int;

}

我想没有一个Java法度榜样员会觉得上面的Java代码存在问题。然则所有严谨的C++法度榜样员则顿时指出:上面这个C++法度榜样有问题,它存在内存透露。然则我本日想和大年夜家交流的一个不雅念是:这个C++法度榜样没有什么问题。

DocX法度榜样的内存治理

DocX是我开拓的一个文档撰写对象。这里有关于它的一些先容。在这一小节里,我要谈谈我在DocX中考试测验的另类内存治理措施。

DocX的总体流程是:

读入一个C++源代码(或头)文件(.h/.c/.hpp/.cpp等),阐发此中的注释,提取并天生xml文档。

经由过程xslt变换,将xml文档转换为htm。

阐发源代码中的所有include指令,取得响应的头文件路径,假如某个头文件没有阐发过,跳到1反复这些步骤。

着末所有天生的htm打包天生chm文件。

一开始,我象Java/C#法度榜样员做的那样,我的代码中所有的new均不斟酌delete。当然,它不停运作得很好,直到有一天我的文档累计到了必然程度后。正如我们预见的那样,DocX法度榜样运行崩溃了。

那么,怎么办呢?找到所有必要delete的地方,补上delete?

这着实并不必要。在前面,我给大年夜家先容了AutoFreeAlloc(拜见《C++内存治理厘革(2):最袖珍的垃圾收受接收器》),大概有人在嘀咕,这样一个内存分配器到底有何感化。——那么,现在你顿时可以看到它的范例用法之一了:

对付我们的DocX崩溃后,我只是做了以下篡改:

加一个全局变量:std::AutoFreeAlloc alloc;

所有的new Type(arg1, arg2, …, argn),改为STD_NEW(alloc, Type)(arg1, arg2, …, argn);

所有的new Type[n],改为STD_NEW_ARRAY(alloc, Type, n);

每处置惩罚完一个源代码文件时,调用一次alloc.clear();

搞定,自此之后,DocX再也没有内存透露,也不再有碰到内存不够而崩溃的情形。

只读DOM模型(或容许少量改动)的建立

在《文本分析的三种范例设计模式》一文中我保举大年夜家应用DOM模型去进行文件操作。并且平日环境下,这个DOM模型是只读DOM模型(或容许少量改动)。

对付只读DOM模型,应用AutoFreeAlloc是极其方便的。全部DOM树涉及的内存统一由同一个AutoFreeAlloc实例进行分配。大年夜体如下:

class Document;

class ObjectA

{

private:

Document* m_doc;

SubObject* m_c;

public:

ObjectA(Document* doc) : m_doc(doc) {

m_c = STD_NEW(doc->alloc, SubObject);

}

* getC() {

return m_c;

}

};

class Document

{

public:

AutoFreeAlloc alloc;

private:

ObjectA* m_a;

ObjectB* m_b;

public:

ObjectA* getA() {

if (m_a == NULL)

m_a = STD_NEW(alloc, ObjectA)(this);

return m_a;

}

};

经由过程这种要领创建的DOM模型,只要你删除了Document工具,全部DOM树自然就被删除了。你根本不必要担心此中有任何内存透露的可能。

假如C++象Java/C#那样有足够富厚的元信息,那么Object::clone历程就可以象Java/C# 等说话那样自动完成。这些元信息对付GC历程的用场无非在于,我们可以遍历全部活动工具的聚拢,然后把这些活动工具复制一份。没有复制过来的工具自然而然就被丢弃了。

GC的道理便是这么简单。没有元信息也不要紧,只要我们要求每个由GC托管的工具支持clone函数,统统就ok了。对付一个繁杂法度榜样,要求每个工具供给clone函数不见得是什么过分的要求,clone函数也不光有gc历程才必要,很多工具在设计上天然就必要clone。

弥补阐明

关于全局AutoFreeAlloc变量

我小我异常不保举应用全局变量(除非是常量:不必然用const修饰,指的是颠末必然初始化步骤后就不在改动的变量)。上面只是对付小型的单线程法度榜样偷懒才这样做。

关于用AutoFreeAlloc实现通用型的GC

请留意我没有评论争论过于细节的器械。假如你抉择选择这种做法,请仔细推敲细节。可以预见的一些细节有:

AutoFreeAlloc与线程模型(ThreadModel)。AutoFreeAlloc关注点在于快,它平日不涉及跨线程问题。然则假如要作为通用型的GC,这一点不能不斟酌。为了机能,保举每个线程自力治理内存,而不要应用互斥体。

机能优化。可以斟酌象Java的GC那样,应用两个AutoFreeAlloc,把工具划分为年轻代和大哥代。

系列文章:

涅磐更生 C++内存治理厘革

C++内存治理厘革(2):最袖珍的垃圾收受接收器

C++内存治理厘革(4): boost::object_pool

您可能还会对下面的文章感兴趣: