前言
上一篇的精简版,方便快速复习
一、四个层面的基本用法
1.1 malloc
使用方法:
void* p1=malloc(512);//512 bytes
free(p1);
1.2 new/delete
使用方法:
complex<int>* p2=new complex<int>;
delete p2;
1.2.1 new/delete expression
- new expression
# code a
Complex* pc=new Complex(1,2);
# code b
Complex* pc;
try{
void* mem =operator new(sizeof(Complex));//allocate
pc=static_cast<Complex*>(mem);//cast
pc->Complex::Complex(1,2);//construct,只有编译器可以这样调用
}
catch(std::bad alloc){
//若allocation失败就不运行constructor
}
- delete expression
1.2.2 Array new/delete
- 使用方式
- cookie记录整块的长度
- 若使用array new 后,最后delete不加 [ ],cookie记录的长度并没有随之改变,因此上图所示绿色部分是不会有内存泄漏的,都会回收到操作系统,
内存泄露真正发生在调用析构函数的次数上
,如上例子所示,加[ ]会调用3次析构函数,不加[ ]只调用一次析构函数,但是由于complex object是复数,内部无指针,因此此时delete不加[ ],只调用一次析构函数就足够了,不需要回收其他地方的内存,只需要回收绿色部分,也不会发生内存泄露 - 泄漏举例
1、string内部有一根指针
2、若使用array new 后,最后delete不加 [ ],内存泄露发生在下图绿色部分三个箭头指向的地方
注意
: - new包括两步,分配内存和构造函数
- 指针psa在栈上,指向new申请的内存(即图示绿色部分)
- 绿色部分是通过new的第一步分配内存得到的
- 绿色部分指向的三个白色长条是通过构造函数得到的
1.3 ::operator new/::operator delete
使用方法:
void* p3=::operator new(512);
::operator delete(p3);
1.31重载::operator new/::operator delete
- vc6源码
- 重载
1.32 重载operator new/operator delete
1.33 重载operator new[]/operator delete[]
1.4 C++标准库提供的allocators
- gunc为2.9版本
1.5 调用顺序及关联
- 宏观关系
- 调用关系
- 容器中的使用
二、G2.9 std::alloc运行模式(经典)
小型内存管理:
- 减少malloc调用次数
- 降低cookie用量
- 内存池提升速度,降低浪费率
2.1 特点
- freelist管理16种大小的链表
- 超过alloc负责的大小会交给malloc处理
- 被要求分配内存不是8的倍数,会被调整为8的倍数
- 每次分配40个,实质使用20个,剩余20个备用,下次分配内存将会切割这部分备用的20个
2.2 内嵌指针embedded pointers
2.2.1匿名union的使用
- note:
//定义union,
//第一种方式:定义了一个union类型,并且定义了一个属于该类型的对象un,因此sizeof(X)=4
class X{
public:
union UN{
int m_nX;
char* pchar;
}un;
};
//第二种方式:定义了一个union类型,但并没有定义属于该类型的任何对象,
//因此理论上sizeof(X)=0,但实际上sizeof(X)=1
class X{
public:
union UN{
int m_nX;
char* pchar;
};
};
//第三种方式://定义了一个匿名的union类型,因此也就只能在X内部使用了,
//并且此种情况隐含着已经在X中定义了一个属于该匿名union类型的象,
//因此sizeof(X)=4,并且此种情况最为特殊,可以直接通过类X的对象来使用m_nX和pchar,
//例如X x;x.m_nX=10;x.pchar="Hello World!";
class X{
public:
union {
int m_nX;
char* pchar;
};
};
-
对于前两种方式,都在类的内部定义了一个新的具有名字的型别,因此可以用这种新的类型来定义对应于该类型的对象,例如:
X::UN myun;
但是这种定义是要求类内部的union在定义时的修饰符为public,否则就不能在类外部定义属于他们的对象,而只能在给类X内部使用了。同理也可以知道在类内部通过typedef定义出来的新型别也是如此。 -
需要说明的是,union用类里以第三种定义的方式出现的话,会有很奇妙的效果,非常奇妙。m_nX和pchar共享一块4个字节的内存,只要不是同时需要m_nX和pchar出现的情况都可以只利用它们其中的一个,从而节省了内存开销。
2.2.2 在G2.9 std::alloc中的使用
2.3 详细过程
- 1
- 2
- 3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
- 11(修改系统内存至1 0000)
- 12
- 13
- 思考
三、 malloc/free
3.1、vc6内存分配
- _heap_init(…)分配16个头
- _ioinit()第一次内存分配,256字节(100h)
- _sbh_alloc_block()将大小调整为16的倍数
- _sbh_alloc_new_region()每个头申请内存,并添加两根指针,一个指向管理单元,一个指向可用内存(1M,虚的)
- sbh_alloc_new_group()可用内存切片
- _crtGetEnvironmentStringsA第二次申请内存并分配
3.11分配
3.12释放
3.13再分配
3.2、内存管理之区域合并
- 上下cookie的存在,方便了 两个相邻区域内存的 合并回收
3.3、总结
- 将内存分层管理,更有利于归还内存给操作系统,因为块越小,遇到回收的概率越大
- 判断全回收:通过GROUP的cntEntnes的值来判断。若为0,则可全回收
- defering推迟回收:
- _sbh_pHeaderDefer是個指针,指向一個全回收 group所属的Header。这個group原本應被释放,但暂保留(延缓释放)。当再有第二個全回收 group出现,SBH才释放道個Defer group,并将新出现的全回收 group般为Defer。
- 如果尚未出现第二個全回收group而又从Defer group取出block完成分配,Defer指针会被取消(设为NULL)
- _sbh_indGroupDefer是個索引,指出Region中哪個 group(#0-#31)是Defer.
- 当你归还(释放)所有内存块,SBH系统将呈现什麽面貌?初始状态
- VC malloc 和GCC allocator