C++内存打点厘革(3):另类内存打点
当前位置:以往代写 > C/C++ 教程 >C++内存打点厘革(3):另类内存打点
2019-06-13

C++内存打点厘革(3):另类内存打点

C++内存打点厘革(3):另类内存打点

副标题#e#

最简朴的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再也没有内存泄漏,也不再有碰着内存不敷而瓦解的景象。


#p#副标题#e#

只读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树自然就被删除了。你基础不需要担忧个中有任何内存泄漏的大概。

另类内存打点的见识

通过以上内容,我试图向各人叙述的一个概念是:

有了AutoFreeAlloc后,C++措施员也可以象GC语言的措施员一样斗胆new而不需要忌惮什么时候delete。

展开来讲,可以有以下结论:

假如你措施的空间巨大度为O(1),那么只new不delete是没有问题的。

假如你措施的空间巨大度为O(n),而且是简朴的n*O(1),那么可以用AutoFreeAlloc简化内存打点。

假如你措施的空间巨大度为O(t),个中t是措施运行时间,而且你不能确定措施执行的总时间,那么AutoFreeAlloc并不直接适合你。较量典范的例子是Word、Excel等文档编辑类的措施。

用AutoFreeAlloc实现通用型的GC

AutoFreeAlloc对内存打点的情况举办了简化,这种简化情况是常见的。在此情况下,C++措施员得到了无可相比的机能优势。虽然,在一般景象下,AutoFreeAlloc并不合用。

那么,一个通用的半自动GC情况在C++是否大概?《C++内存打点厘革》系列的焦点就是要汇报你:虽然可以。而且,我们推荐C++措施员利用半自动的GC,而不是Java/C# 中的那种GC。

通用的半自动GC情况可以有许多种成立方法。这里我们简朴聊一下如何利用AutoFreeAlloc去成立。

我们知道,利用AutoFreeAlloc,将导致措施跟着时间推移,慢慢地吃掉可用的内存。假设此刻已经达到我们配置的临界点,我们需要开始gc。整个进程和Java等语言的gc其实完全雷同:通过一个根工具(Object* root),得到所有勾当着的工具(Active Objects),将它们复制到一个新的AutoFreeAlloc中:

#p#分页标题#e#

Object* gc(AutoFreeAlloc& oldAlloc, Object* root, AutoFreeAlloc& newAlloc)
{
Object* root2 = root->clone(newAlloc);
oldAlloc.clear();
return root2;
}

假如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,把工具分别为年青代和大哥代。

    关键字:

在线提交作业