[C++ primer]优化内存分配

C++的内存分配是一种类型化操作:new为特定类型分配内存,并在新分配的内存中构造该类型的一个对象。new表达式自动运行合适的构造函数来初始化每个动态分配的类类型对象。

new基于每个对象分配内存的事实可能会对某些类强加不可接受的运行时开销,这样的类可能需要使用用户级的类类型对象分配能够更快一些。这样的类使用的通用策略是,预先分配用于创建新对象的内存,需要时在预先分配的内存中构造每个新对象。另外一些类希望按最小尺寸为自己的数据成员分配需要的内存。

在每种情况下(预先分配内存以保存用户级对象或者保存类的内部数据)都需要将内存分配与对象构造分离开。将内存分配与对象构造分离开的明显的理由是,在预先分配的内存中构造对象很浪费,可能会创建从不使用的对象。当实际使用预先分配的对象的时候,被使用的对象必须重新赋以新值。更微妙的是,如果预先分配的内存必须被构造,某些类就不能使用它。例如,考虑vector,它使用了预先分配策略。如果必须构造预先分配的内存中的对象,就不能有基类型为没有默认构造函数的vector——vector没有办法知道怎样构造这些对象。

1、C++中的内存分配

C++中,内存分配和对象构造紧密纠缠,就像对象和内存回收一样。使用new表达式的时候,分配内存,并在该内存中构造一个对象;使用delete表达式的时候,调用析构函数撤销对象,并将对象所用内存返还给系统。

接管内存分配时,必须处理这两个任务。分配原始内存时,必须在该内存中构造对象;在释放该内存之前,必须保证适当地撤销这些对象。

注:对未构造的内存中的对象进行赋值而不是初始化,其行为是未定义的。对许多类而言,这样做引起运行时崩溃。赋值涉及删除现存对象,如果没有现存对象,赋值操作符中的动作就会有灾难性效果。

C++提供以下两种方法分配和释放未构造的原始内存:

1)allocator类,它提供可感知类型的内存分配。这个类支持一个抽象接口,以分配内存并随后使用该内存保存对象。

2)标准库中的operatornew 和 operatordelete,它们分配和释放需要大小的原始的、未类型化的内存。

C++还提供不同的方法在原始内存中构造和撤销对象。

1)allocator类定义了名为construct和 destroy的成员,其操作正如它们的名字所指出的那样:construct成员在未构造内存中初始化对象,destroy 成员在对象上运行适当的析构函数。

2)定位new表达式接受指向未构造内存的指针,并在该空间中初始化一个对象或一个数组。

3)可以直接调用对象的析构函数来撤销对象。运行析构函数并不释放对象所在的内存。

4)算法uninitialized_fill和uninitialized_copy像 fill和 copy 算法一样执行,除了它们的在目的地构造对象而不是给对象赋值之外。

2、allocator类

allocator类是一个模板,它提供类型化的内存分配以及对象构造与撤销。

allocator类将内存分配和对象构造分开。当allocator对象分配内存的时候,它分配适当大小并排列成保存给定类型对象的空间。但是,它分配的内存是未构造的,allocator的用户必须分别construct和 destroy放置在该内存中的对象。

3、operator new函数和operator delete 函数

使用new表达式:string*  sp =new  string(“initialized”);

实际发生3个步骤:

1)调用名为operator new的标准库函数。分配足够大的原始的未类型化的内存,以保存指定类型的对象。

2)运行该类型的一个构造函数,用指定初始化式构造对象。

3)返回指向新分配并构造对象的指针。

(总结:分配内存,构造对象,返回对象指针)

使用delete操作符delete  sp;删除对象时,发生两个步骤:

1)对指向的对象运行适当的析构函数。

2)调用名为operator delete的标准库函数释放该对象的内存。

(总结:析构对象,释放空间)

:new 表达式与 operator new 函数的区别(是两回事):
1)不能重定义 new 和 delete 表达式的行为;
2)new 表达式获通过调用 operator new 函数得内存,并接着在该内存中构造一个对象;通过执行 delete 表达式撤销一个对象,并接着调用 operator delete 函数,以释放该对象使用的内存。

operator new和operator delete有两个不同的版本。每个版本支持相关的new表达式和delete表达式。

void *operator new(size_t);                 //allocate an object;

vodi *operator new [](size_t);       //allocate an array;

void operator delete(void*);               //free an object;

void operator delete[](void*);       //free an array;

虽然operator new和operator delete的设计意图是供new和delete表达式使用,但是我们仍然可以使用它们获得未构造的内存。这有点类似allocator的allocate和deallocate成员。

一般来说,使用allocator比直接使用operator new 和operator delete 函数更为类型安全。

4、定位new表达式(placement new)

标准库函数 operator new 和 operator delete 是 allocator 的allocate 和 deallocate 成员的低级版本,它们都分配但不初始化内存。

定位 new 表达式在已分配的原始内存中初始化一个对象,它与 new 的其他版本的不同之处在于,它不分配内存。相反,它接受指向已分配但未构造内存的指针,并在该内存中初始化一个对象。实际上,定位 new 表达式使我们能够在特定的、预分配的内存地址构造一个对象。

定位new表达式形式:

new (place-address) type;                                //在指针p处构造type类型对象;

new (place-address) type(initializer list);           //在指针p处用初始化列表构造对象;

其中 place_address 必须是一个指针,而 initializer-list 提供了(可能为空的)初始化列表,以便在构造新分配的对象时使用。

使用定位new表达式比使用allocator类的construct成员更灵活。定位new在初始化一个对象的时候,它可以使用任何构造函数,并直接建立对象,而construct函数总是使用复制构造函数。

5、显示析构函数的调用

我们可以使用析构函数的显式调用作为调用 destroy 函数的低级选择。显式调用析构函数的效果是适当地清除对象本身。但是,并没有释放对象所占的内存,如果需要,可以重用该内存空间。

对于使用定位new表达式构造对象的程序 ,显示调用析构函数:

for (T* p=first_free;p!=elements;/*empty*/)
    p->~T();      //call the destructor;
时间: 2024-11-09 05:06:13

[C++ primer]优化内存分配的相关文章

C++ Primer 学习笔记_98_特殊工具与技术 --优化内存分配

特殊工具与技术 --优化内存分配 引言: C++的内存分配是一种类型化操作:new为特定类型分配内存,并在新分配的内存中构造该类型的一个对象.new表达式自动运行合适的构造函数来初始化每个动态分配的类类型对象. new基于每个对象分配内存的事实可能会对某些类强加不可接受的运行时开销,这样的类可能需要使用用户级的类类型对象分配能够更快一些.这样的类使用的通用策略是,预先分配用于创建新对象的内存,需要时在预先分配的内存中构造每个新对象. 另外一些类希望按最小尺寸为自己的数据成员分配需要的内存.例如,

C++ Primer 学习笔记_99_特殊工具与技术 --优化内存分配[续1]

特殊工具与技术 --优化内存分配[续1] 三.operator new函数和operator delete 函数 – 分配但不初始化内存 首先,需要对new和delete表达式怎样工作有更多的理解.当使用new表达式 string *sp = new string("initialized"); 的时候,实际上发生三个步骤: 1)首先,表达式调用名为operator new 的标准库函数,分配足够大的原始的未类型化的内存,以保存指定类型的一个对象; 2)接下来,运行该类型的一个构造函数

C++ Primer 学习笔记_100_特殊工具与技术 --优化内存分配[续2]

特殊工具与技术 --优化内存分配[续2] 七.一个内存分配器基类 预先分配一块原始内存来保存未构造的对象,创建新元素的时候,可以在一个预先分配的对象中构造:释放元素的时候,将它们放回预先分配对象的块中,而不是将内存实际返还给系统.这种策略常被称为维持一个自由列表.可以将自由列表实现为已分配但未构造的对象的链表. 我们将定义一个名为 CachedObj 的新类来处理自由列表.像 QueueItem 这样希望优化其对象分配的类可以使用 CachedObj 类,而不用直接实现自己的 new 和 del

C++ Primer 学习笔记_98_非一般工具与技术 -优化内存分配

特殊工具与技术 --优化内存分配 引言: C++的内存分配是一种类型化操作:new为特定类型分配内存,并在新分配的内存中构造该类型的一个对象.new表达式自动运行合适的构造函数来初始化每个动态分配的类类型对象. new基于每个对象分配内存的事实可能会对某些类强加不可接受的运行时开销,这样的类可能需要使用用户级的类类型对象分配能够更快一些.这样的类使用的通用策略是,预先分配用于创建新对象的内存,需要时在预先分配的内存中构造每个新对象. 另外一些类希望按最小尺寸为自己的数据成员分配需要的内存.例如,

C++ Primer 学习笔记_98_特殊的工具和技术 --优化内存分配

特殊的工具和技术 --优化内存分配 引言: C++的内存分配是一种类型化操作:new为特定类型分配内存,并在新分配的内存中构造该类型的一个对象.new表达式自己主动执行合适的构造函数来初始化每一个动态分配的类类型对象. new基于每一个对象分配内存的事实可能会对某些类强加不可接受的执行时开销,这种类可能须要使用用户级的类类型对象分配能够更快一些. 这种类使用的通用策略是,预先分配用于创建新对象的内存,须要时在预先分配的内存中构造每一个新对象. 另外一些类希望按最小尺寸为自己的数据成员分配须要的内

c++14对内存分配性能的重大优化

Table of Contents 1. 本质需求 2. 存在的问题 3. 解决方案 简述, C++14标准对内存优化的描述修改, 会让编译器引入类似TCMalloc的内存分配优化策略, 而不拘泥于原来的有一个new语句,就分配一次内存的傻傻的情况. 因此有理由相信用C++14的编译器编译出来的c++程序在内存分配上性能会有较多提升. 下面的文字来源于clang编译器提供的文档, 我对其主要内容进行了意译. 个人感觉是, 不再需要引入TCMalloc库来帮助提升性能, 直接使用c++14就行了.

Weblogic admin server与manager server内存分配缺陷优化

1.admin server与manager server内存分配缺陷描述 Weblogic服务器一般会为每一个业务系统设计一个或多个域(domain),每一个域(domain)服务主体必须由Admin server和Manage Server两类Server组成,两类Server都需要占用一定的内存资源(人工配置),Manage Server负责运行业务,Admin Server则只负责管理Manage Server,只是在启动Weblogic和需要调整Weblogic配置时才使用,启动Web

Android内存优化1 了解java内存分配 1

开篇废话 今天我们一起来学习JVM的内存分配,主要目的是为我们Android内存优化打下基础. 一直在想以什么样的方式来呈现这个知识点才能让我们易于理解,最终决定使用方法为:图解+源代码分析. 欢迎访问我的个人博客:senduo's blog 希望能在我们平时开发写代码的时候,能够知道当前写的这段代码,内存方面是如何分配的. 我们深知,一个Java程序员在很多时候根本不用操心内存的释放,而是依靠JVM去管理,以前写C++代码的时候,却要时刻记着new的空间要及时释放掉,不然程序很容易出现内存溢出

C++ primer plus读书笔记——第12章 类和动态内存分配

第12章 类和动态内存分配 1. 静态数据成员在类声明中声明,在包含类方法的文件中初始化.初始化时使用作用域运算符来指出静态成员所属的类.但如果静态成员是整形或枚举型const,则可以在类声明中初始化. P426-P427类静态成员的声明和初始化 //strnbad.h class StringBad { private: static int num_strings; … }; //strnbad.cpp int StringBad::num_strings = 0; 不能在类声明中初始化静态