Chapter 3 C/C++ Video Memory Management and Templates前言:
视频内存管理是 C++ 中最具争议的问题之一。显存管理在 C++ 中无处不在,几乎每个 C++ 程序都会发生显存泄漏。因此,如果你想成为 C++ 高级,显存管理是必须的。需要。
文章目录
一、C/C++ 中的程序区定义
了解动态图形在 C/C++ 中的工作原理对于成为合格的 C/C++ 程序员至关重要。 C/C++程序中的显存分为六个部分:
⭐描述
栈也叫栈——非静态局部变量/局部变量/函数参数/返回值等。栈是上下的,通常有指定的大小。 Linux栈是一个8M的显存映射段,是一种高效的I/O映射方式,用来加载一个共享的动态内存库。用户可以使用系统套接字来创建共享的共享视频内存,用于进程间通信。堆用于程序运行时动态分配内存,堆可以上下。堆比较大,通常有一个接近2G左右的空间数据段——存储全局数据和静态数据。代码段——可执行代码/只读常量(“helloworrld”)。 二、C语言中的动态内存管理方法
malloc/calloc/realloc/free
功能说明
void*malloc(intnum);
在堆区分配一块指定大小的显存空间来存储数据。这个内存空间在函数执行后不会被初始化,它们的值是未知的。
void*calloc(intnum,intsize);
在显存中动态分配num个size size的连续空间,并将每个字节初始化为0。相当于malloc+memset
void*realloc(void*address,intnewsize);
此函数重新分配显存并将显存扩展为newsize。如果空间足够,就在原地展开,如果空间不够,就在其他地方展开
voidfree(void*address);
该函数释放address指向的显存块,即动态分配的显存空间。
三、C++显存管理方法
C语言显存管理方法在C++中可以继续使用,但是有些地方力不从心,使用起来比较麻烦c语言中内存的申请和释放,所以C++提出了自己的显存管理方法:通过动态显存管理new 和 delete 运算符。
1.新建/删除操作外部类型
对于外部类型,new/delete 和 malloc/free 没有区别,只是语法不同。
int* p1 = (int*)malloc(sizeof(int));
// 动态申请一个int类型的空间
int* p2 = new int;
int* p3 = new int[5];// 动态申请5个int类型的空间
int* p4 = new int(10); // 动态申请一个int类型的空间并初始化为10
int* p5= new int[5]{1,2,3};// C++11支持new[]用{}初始化,c++98不支持
free(p1);
delete p2; //new/delete,new[]/delete[]一定要匹配,否则可能会出错
delete[] p3;
delete p4;
delete[] p5;
应用和释放单个元素的空间,使用new和delete运算符,应用和释放连续空间,使用new[]和delete[],注意:匹配使用。
2.新建/删除操作自定义类型
new/delete 和 malloc/free 申请自定义类型的空间时,最大的区别是 new/delete 会调用构造函数和析构函数,不仅为自定义类型打开空间,new/delete 的目的是为自定义类型。
//1、堆上申请空间 2、调用析构函数初始化
A* p1 = new A;
A* p2 = new A(10);
A* p3 = new A[2];
//1、调用析构函数清理对象中资源 2、释放空间
delete p1;
delete p2;
delete[]p3;
总结:
1、在C++中,如果申请外部类型对象或链表,malloc和new没有区别
2、如果是自定义类型,差别很大,new是开空间+初始化,delete是销毁清除+释放空间,malloc和free只是开空间+释放空间
3、建议在C++中,无论是外部类型的应用发布还是自定义类型,都尽量使用new和delete。
4、新的失败不需要检查返回值,它会抛出异常。
3.malloc/free和new/delete的异同
共同点是,它们都是从堆中申请空间,需要用户自动释放。
区别在于:
malloc 和 free 是函数,new 和 delete 是运算符。 malloc申请的空间不会被初始化,但是new可以初始化。 malloc在申请空间的时候,需要自动估计空间的大小并进行转移。新建只需要跟随空间的类型。如果有多个对象,[]可以手动指定对象的数量。 malloc的返回值为void*,使用时必须转换,不需要new,因为new后面是空格的类型。 malloc申请空间失败时返回NULL,所以使用时必须为空,new不需要,但是new需要捕获异常。申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数和析构函数,而new申请空间后会调用构造函数完成对象的初始化,delete会调用释放空间之前的析构函数。完成空间内资源的清理。 4.哪些是显存泄漏以及显存泄漏的危害
什么是显存泄漏:显存泄漏是指遗漏或错误导致程序无法释放不再使用的显存的情况。显存泄漏并不是说显存在数学上消失了,而是应用程序分配了一定的显存后,由于设计错误,失去了对显存的控制,丢了针,从而造成了显存的浪费记忆。
显存泄漏的危害:显存泄漏发生在常年运行的程序中,如操作系统、后台服务等,显存泄漏会导致响应越来越慢,并最终陷入困境。
四、new 和 delete 运算符1.operatornew 和 operatordelete 函数
new和delete是供用户申请和释放动态显存的运算符。 Operatornew 和 operatordelete 是系统提供的全局函数。 new调用底层operatornew全局函数申请空间,delete使用底层operatordelete全局函数释放空间。
⭐operatornew 实际上是通过 malloc 申请空间的。如果malloc申请空间成功,则直接返回。否则,将执行用户提供的空间不足的响应。如果用户提供了这个动作,应用程序将继续,否则将抛出异常。封装了malloc,失败时抛出异常,符合C++封装和抛出异常的机制。 operatordelete 最终通过 free 释放空间。
注意:一般情况下,不需要重载operatornew和operatordelete,除非在申请和释放空间时有个别特殊要求。比如在使用new和delete申请和释放空间的时候,复制一些日志信息,可以简单的帮助用户检查是否有显存泄露。
2.new和delete的实现原理
外部类型:
如果申请外部类型的空间,new和mallocc语言中内存的申请和释放,delete和free基本类似,区别在于:new/delete为单个元素申请和释放空间,new[]和delete[]申请的是一个连续的空间,但是当new申请空间失败时,会抛出异常,malloc会返回NULL。
自定义类型:
new原理1.调用operatornew函数申请空间。 2.在申请的空间上执行构造函数,完成对象的构造。
删除原理
1.在空间上执行析构函数,完成对象内资源的清理。 2.调用operatordelete函数释放对象空间。
newT[N]的原理
1.调用operatornew[]函数,实际调用operatornew[]中的operatornew函数,完成N个对象空间的应用。 2.在请求的空间上执行构造函数N次。
delete[]的原理
1. 在释放的对象空间上执行N个析构函数,完成N个对象中资源的清理。 2.调用operatordelete[]释放空间,实际上调用operatordelete[]中的operatordelete释放空间。
3.定位新表达式(placement-new)
定位new表达式是调用构造函数在分配的原始显存空间中初始化一个对象。
使用格式:
new(place_address)type 或 new(place_address)type(initializer-list)
place_address 必须是指针,initializer-list 是该类型的初始化列表
使用场景:
定位新表达式在实践中通常与显存池配合使用。由于显存池分配的显存没有初始化,如果是自定义类型的对象,需要使用new的定义表达式显示构造函数进行初始化。
A* p = (A*)operator new(sizeof(A));//p现在指向的只不过是与A对象相同大小的一段空间,还不能算是一个对象,因为构造函数没有执行
new(p)A(10); //显示调用构造函数初始化这块空间
p->~A(); //显示调用析构函数
operator delete(p);