1、对象构造前的空间配置与对象析构后的空间释放,由<stl_alloc.h>负责。SGI对此设计哲学如下:
a)向system heap要求空间
b)考虑多线程状态
c)考虑内存不足时的应变措施
d)考虑过多“小型区块”可能造成的内存碎片(fragment)问题
C++的内存配置操作::operator new(),内存释放基本操作是::operator delete()这两个全局函数相当于C的malloc()和free()函数。是的,SGI正是以malloc()和free()完成内存的配置与释放的。
2、SGI双层级别的配置器
考虑到小型区块可能造成的内存碎片问题,SGI设计了双层级别的配置器。
第一级配置器:直接使用malloc()和free(),使用malloc()、free()、realloc()等C函数执行实 际的内存配置、释放、重配置操作。它不是直接使用C++ new-handler机制。因此并不是使用::operator new来配置内存的。
第二级配置器:视情况采用不同的策略:
1)当配置的区块超过128bytes时,视之为足够大,此时便调用一级配置器。
2)当配置区块小于128bytes时,视之为“过小”,为了降低额外负担(overhead),便采用复杂的memory pool(内存池)管理方式,而不再求助于第一级配置器。
a)维护16个自由链表(free lists)负责16种小型区块的配置能力。
b)内存池(memory pool)以malloc()配置而得。
c)如果内存不足,则转去调用第一级配置器,因为第一级配置器那里有处理程序。- --------不断尝试释放、配置、再释放、再配置
3、C++ new-handler机制
所谓C++ handler机制就是你可以要求系统在内存配置需求无法满足时,调用一个你所指定的函数。换句话说,一旦::operator new无法完成任务,在抛出std::bad_alloc异常之前会先调用由用户事先指定的处理例程。该处理例程就被称为new-handler。
4、一般而言,我们所习惯的C++内存配置操作和释放操作是这样的:
class Foo { Foo *pf = new Foo; delete pf; };
这其中的new实际上包含两个阶段操作:
(1)new表达式调用一个,名为::operator new(或者::operator new[])的标准库函数该函数分配一个足够大的、原始的、未命名的内存空间以便存储特定类型的对象(或者数组)。
(2)编译器运行相应的构造函数以便构造这些对象,并为其传入初始值(换句话说就是调用Foo::Foo()构造对象内容)。
这其中delete实际上也是分两个阶段的操作:
(1)对pf所指向的对象或数组执行相应的析构函数。
(2)调用::operator delete(或者::operator delete [])释放内存。
5、为了精密分工,STL allocator决定将这两个阶段分开来,内存配置由alloc::allocate()负责,内存构造由alloc::deallocate()负责;对象构造由::construct()负责,对象析构由::destroy()负责。
STL标准告诉我们,配置器定义于<memory>中,SGI <memory>内含以下两个文件:
#include <stl_alloc.h> //负责内存空间配置与释放 #include <stl_construct.h> //负责对象内容的构造与析构
6、术语----placement new(也叫定位new)
如果你想在一个已经分配的内存中创建一个对象,使用new是不行的。placement new允许你在一个已经分配的内存中构造一个新的对象。
7、关于析构函数
如果用户不定义自己的析构函数,而是使用系统默认的析构函数,则说明析构函数基本没有什么作用(但默认会被调用)我们称之为trivial destruvtor.
destroy函数会判断将要释放的迭代器所指向的对象的类型有没有trivial destructor;若有,则什么也不做。若没有,则执行真正的destroy
8、怎样单独分配一个原始的为构造的内存区域?(如何调用原生态的operator new)
//如果需要的是void类型,size_t是具体大小 void *p = operator new(size_t); //如果需要的是int类型 int *p = static_cast<int *>(operator new(size_of(int)));
因为由原生态operator new分配的内存所返回的指针都是void类型的,所以需要进行强制类型转换