C++:内存管理——从平地到万丈高楼

目录


前言

本篇是学习记录,比较冗杂,快速掌握大概,可阅读精简版


第一讲 primitives

1、C++ memory primitives

在这里插入图片描述

2、四个层面的基本用法

malloc

在这里插入图片描述

new/delete

在这里插入图片描述

::operator new/::operator delete

在这里插入图片描述

C++标准库提供的allocators

  • gunc为2.9版本
    在这里插入图片描述
  • gunc 4.9的其中两个分配器

在这里插入图片描述

调用顺序

在这里插入图片描述

3、new/delete expression

new expression

编译器转为
code b中operator new调用
code a
code b
malloc函数
# code a
Complex* pc=new Complex(1,2);
# code b
Complex* pc;
try{
void* mem =operator newsizeof(Complex));//allocate
pc=static_cast<Complex*>(mem);//cast
pc->Complex::Complex(12;//construct,只有编译器可以这样调用
}
catch(std::bad alloc){
//若allocation失败就不软行constructor
}

delete expression

在这里插入图片描述

Ctor&Dtor (构造函数和析构函数)直接调用

不能直接调用构造函数和析构函数。因为虽然直接调用析构函数可以编译通过,但是构造函数大部分情况下编译不通过,因此两个函数不能成对通过的话,代码运行会crash。

#欲直接用ctor,可用placement newnew(p)Complex(1,2);

4、Array new/delete

使用方式

在这里插入图片描述
在这里插入图片描述

  • cookie记录整块的长度
  • 若使用array new 后,最后delete不加 [ ],cookie记录的长度并没有随之改变,因此上图所示绿色部分是不会有内存泄漏的,都会回收到操作系统,内存泄露真正发生在调用析构函数的次数上,如上例子所示,加[ ]会调用3次析构函数,不加[ ]只调用一次析构函数,但是由于complex object是复数,内部无指针,因此此时delete不加[ ],只调用一次析构函数就足够了,不需要回收其他地方的内存,只需要回收绿色部分,也不会发生内存泄露。

泄漏举例

  • string内部有一根指针
  • 若使用array new 后,最后delete不加 [ ],内存泄露发生在下图绿色部分三个箭头指向的地方
    在这里插入图片描述

5、placement new

在这里插入图片描述

6、C++分配内存的途径

应用程序

在这里插入图片描述

容器

在这里插入图片描述

重载::operator new/::operator delete

  • vc6源码
    在这里插入图片描述
  • 重载
    在这里插入图片描述

重载operator new/operator delete

在这里插入图片描述

重载operator new[]/operator delete[]

在这里插入图片描述

重载new()/delete()

  • 重载 placement new总结
    在这里插入图片描述
  • 例子
    在这里插入图片描述
    在这里插入图片描述

7、Per-class allocator

小型内存管理

  • 减少malloc调用次数
  • 降低cookie用量
  • 内存池提升速度,降低浪费率

匿名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出现的情况都可以只利用它们其中的一个,从而节省了内存开销

static allocator

营你受困於必须为不同的 classes 重寓一遍乎相同的member operator new 和member operator delete时,应该有方法将一個是分配特定尽寸之区块的memory allocator概念包装起来,使它容易被重使用。使得每个allocator object 都是個分配器,它体内维护一個free-lists;不同的allocator objects维不同的free-lists。

8、new handler

nothrow形式

当operator new没能力为你分配出你所申请的memory,会抛一個std::bad_alloc exception。某些老版编译器则是返回0,你仍然可以令编译器那麽做:new(nothrow)Foo;//此种为nothrow形式

new handler

抛出exception之前先(不只一次)调用一個可由 client指定的handler,以下是new handler的形式和定方法:
在这里插入图片描述

  • 设计良好的new handler只有两个选择:
  1. 镶更多memory可用
  2. 调用abortO或exitO

9、=default,=delete

在这里插入图片描述

第二讲 std::allocator

1、各主流编译器的标准分配器

1、vc6 标准分配器

在这里插入图片描述

2、BC5 标准分配器

在这里插入图片描述

3、G2.9 标准分配器

在这里插入图片描述

  • 但是G2.9容器使用的分配器,不是std::allocator 而是std::alloc

4、G4.9 标准分配器

在这里插入图片描述

  • G4.9 中的_pool_alloc去除了cookie(8字节)

2、 G2.9 std::alloc运行模式

特点

  • freelist管理16种大小的链表
  • 超过alloc负责的大小会交给malloc处理
  • 被要求分配内存不是8的倍数,会被调整为8的倍数
  • 每次分配40个,实质使用20个,剩余20个备用,下次分配内存将会切割这部分备用的20个
    在这里插入图片描述

内嵌指针embedded pointers

在这里插入图片描述

详细过程

  • 1
    在这里插入图片描述
  • 2
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200803211417254.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzk5MTgyNg==,size_16,color_FFFFFF,t_70
  • 3

在这里插入图片描述

  • 4
    在这里插入图片描述

  • 5
    在这里插入图片描述

  • 6
    在这里插入图片描述

  • 7
    在这里插入图片描述

  • 8
    在这里插入图片描述

  • 9
    在这里插入图片描述

  • 10

在这里插入图片描述

  • 11(修改系统内存至1 0000)
    在这里插入图片描述
  • 12
    在这里插入图片描述
  • 13
    在这里插入图片描述
  • 思考
    在这里插入图片描述

G2.9 std::alloc源码剖析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

G2.9 std::alloc小应用

  • G2.9的容器默认使用std::alloc
    在这里插入图片描述

第三讲 malloc/free

1、vc6和vc10的malloc比较

  • vc6的SBH,在vc10中被放到了heapalloc()中

2、vc6内存分配

  • _heap_init(…)分配16个头
  • _ioinit()第一次内存分配,256字节(100h)
  • _sbh_alloc_block()将大小调整为16的倍数
  • _sbh_alloc_new_region()每个头申请内存,并添加两根指针,一个指向管理单元,一个指向可用内存(1M,虚的)
  • sbh_alloc_new_group()可用内存切片
  • _crtGetEnvironmentStringsA第二次申请内存并分配
    在这里插入图片描述

分配

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

释放

在这里插入图片描述
在这里插入图片描述

再分配

在这里插入图片描述

在这里插入图片描述

3、内存管理之区域合并

  • 上下cookie的存在,方便了 两个相邻区域内存的 合并回收
    在这里插入图片描述

4 、总结

  1. 将内存分层管理,更有利于归还内存给操作系统,因为块越小,遇到回收的概率越大
  2. 判断全回收:通过GROUP的cntEntnes的值来判断。若为0,则可全回收
  3. 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.
  1. 当你归还(释放)所有内存块,SBH系统将呈现什麽面貌?初始状态
  2. VC malloc 和GCC allocator
    在这里插入图片描述

在这里插入图片描述

第四讲 loki::allocator

  • gnuc的分配器致命伤就是非常霸道,不归还内存,但是loki的分配器可以还
    在这里插入图片描述

第五讲 other allocators

1、GNU C++对于各allocator的描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、VS2013标准件分配器

  • 平淡如水,仍然调用::operator new()和::operator delete(),实际上什么都没做
    在这里插入图片描述

3、G4.9标准分配器

在这里插入图片描述

4、G4.9 malloc_allocator

在这里插入图片描述

5、G4.9 array_allocator

在这里插入图片描述

  • array_allocator的使用
  1. 先做一个数组,然后使用array_allocator分配内存
    在这里插入图片描述
    或者
  2. 使用new分配一块动态内存,然后使用array_allocator
    在这里插入图片描述

6、G4.9 debug_allocator

在这里插入图片描述

7、G4.9 _pool_alloc

  • G4.9 _pool_alloc就是G2.9的alloc的化身(第二讲的那种分配器),特点就是只拿不还
    在这里插入图片描述
  • 用例
    在这里插入图片描述

8、G4.9 bitmap_allocator

  • bitmap_allocator宏观
    在这里插入图片描述
  • blocks,super-blocks,bitmap,mini-vector简介
    在这里插入图片描述
  • bitmap_allocator分配内存过程
  1. 用了一块
    在这里插入图片描述
  2. 用了63块
    在这里插入图片描述
  3. 还回去一块
    在这里插入图片描述
  4. 如果第一块用光,启动第二块
    在这里插入图片描述
  5. 如果第二块用光,启动第三块
    在这里插入图片描述
  • bitmap_allocator回收内存过程
  1. 第1个super_block全回收
    在这里插入图片描述
  2. 第2个super_block全回收
    在这里插入图片描述
  3. 第3个super_block全回收
    在这里插入图片描述

9、使用G4.9分配器

在这里插入图片描述
在这里插入图片描述

第六讲 其他

1、谈谈const

  • const后置只能加在类成员函数身上,不能加在全局函数身上
    在这里插入图片描述

2、关于new、delete

在这里插入图片描述

重载 ::operator new,::operator delete

        ::operator new[],::operator delete[]

在这里插入图片描述

重载member operator new/delete

在这里插入图片描述

重载member operator new[]/delete[]

在这里插入图片描述

示例

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

重载new(),delete()

  • placement new
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值