【学习笔记】C++内存管理-侯捷


学习笔记源自博览网侯捷大师的C++课程,在原视频及讲义的基础上填充注释。
如有侵权,请联系删除,抱歉。


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

目标:深入源码,学习C++分配内存的基本工具及进阶工具管理内存的方式、STL标准库中分配器管理内存的方式、底层malloc函数管理内存的方式。

从平地到万丈高楼:从最基础的C++语言构件,到高知名度的内存管理器。

基础条件

  • 曾动态分配及使用内存
  • 曾使用C++ STL容器

工具

  • Dev-C++
  • Visual C++ 6.0(Microsoft Visual Studio)

链接

书籍

  • STL源码剖析:chapter2-allocator
  • Modern C++ Design:chapter4-Small Object Allocation
  • Small Memory Software

  • STL Allocators
  • MFC CPlex + CFixedAlloc
  • Boost.Pool
  • Loki SmallObjAllocator
  • VC malloc/free
  • jemalloc
  • tcmalloc

一、primitives-基础工具

1.内存分配的四个层面

C++程序使用内存的方式

类别内存分配内存释放可否重载
C函数malloc()free()不可重载
C++表达式(expression)newdelete不可重载
C++函数::operator new()::operator delete()可重载
C++标准库allocator<T>::allocate()allocator<T>::deallocate()可自由设计
并搭配任何容器

new表达式底层调用operator new()函数,进而调用malloc()函数申请内存;
delete表达式底层调用operator delete()函数,进而调用free()函数释放内存。

示例:C++分配内存的基本工具(primitives)

/* 1.使用malloc分配内存 */
void* p1 = malloc(512);	// 512字节
free(p1);

/* 2.使用new分配内存 */
complex<int>* p2 = new complex<int>; // 1个对象
delete(p2);

/* 3.使用::operator new()分配内存 */
void* p3 = ::operator new(512);	// 512字节
::operator delete(p3);

/* 4.使用C++标准库提供的allocators */
/* 接口存在标准规格,但编译器的实现未完全遵循 */
#ifdef _MSC_VER
// 非静态函数,需通过对象调用,分配3个int型内存
int* p4 = allocator<int>().allocate(3, (int*)0); // 匿名对象调用
allocator<int>().deallocate(p4, 3);
#endif

#ifdef __BORLANDC__
// 非静态函数,需通过对象调用,分配5个int型内存
int* p4 = allocator<int>().allocate(5);	// 匿名对象调用
allocator<int>().deallocate(p4, 5);
#endif

#ifdef __GNUC__	// GCC 2.9
// 静态函数,可通过类名调用,分配512个字节内存
void* p4 = alloc::allocate(512);	// 类名调用
alloc::deallocate(p4, 512);
#endif

#ifdef __GNUC__	// GCC 4.9
// 非静态函数,需通过对象调用,分配7个int型内存
void* p4 = allocator<int>().allocate(7);	// 匿名对象调用
allocator<int>().deallocate((int*)p4, 7);

// 非静态函数,需通过对象调用,分配9个int型内存
void* p5 = __gnu_cxx::_pool_alloc<int>().allocate(9);	// 匿名对象调用
__gnu_cxx::_pool_alloc<int>()deallocate((int*)p5, 9);
#endif

注:使用分配器管理内存时,申请和释放的内存大小必须对应。


2.new/delete表达式

2.1 new表达式

new表达式:先调用malloc()函数申请内存;再调用构造函数。

new表达式底层调用operator new()函数,进而调用malloc()函数申请内存。

示例:编译器调用new表达式的底层操作
Complex* pc = new Complex(1, 2);

Complex *pc;
try {
    /* 1.allocate:调用operator new()申请内存 */
    // 若没有自定义的operator new()函数,则调用全局::operator new()
    void* mem = operator new(sizeof(Complex));
    
    /* 2.cast:静态类型转换 */
    pc = static_cast<Complex*>(mem);
    
    /* 3.construct:调用构造函数 */
    pc->Complex::Complex(1, 2);
} catch (std::bad_alloc) {
    // 若内存分配失败,则不执行构造函数
}

注:通常只有编译器可以直接调用构造函数pc->Complex::Complex(1, 2);

若需要直接调用构造函数,可使用placement newnew(p) Complex(1, 2);

new表达式的原理
请添加图片描述

malloc()函数申请内存失败时,会调用_callnewh()函数,进而调用自定义的new handler。
new handler是可自行设定的回调函数,应在自定义的new handler中释放不必要的内存,以便继续调用malloc()函数成功申请内存。
参考链接:C++new和delete实现原理


2.2 delete表达式

delete表达式:先调用析构函数;再调用free()函数释放内存。

delete表达式底层调用operator delete()函数,进而调用free()函数释放内存。

示例:编译器调用delete表达式的底层操作
delete pc;

/* 1.调用析构函数 */
pc->~Complex();

/* 2.调用operator delete()释放内存 */
operator delete(pc);

全局函数::operator delete()的实现

// 路径:..\vc98\crt\src\delop.cpp
void __cdecl operator delete(void *p) _THROW()
{
    free(p);
}

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值