如何整理网站,选择网站建设公司,cms网站开发,贵州省建设厅公示网站文章目录 1.C/C内存分布回顾2.C内存管理2.1 内存申请2.2 operator new与operator delete函数2.3 定位new表达式 3.关于内存管理的常见知识点3.1 malloc/free和new/delete的区别3.2 内存泄漏 希望读者们多多三连支持小编会继续更新你们的鼓励就是我前进的动力#xff01; 继C语… 文章目录 1.C/C内存分布回顾2.C内存管理2.1 内存申请2.2 operator new与operator delete函数2.3 定位new表达式 3.关于内存管理的常见知识点3.1 malloc/free和new/delete的区别3.2 内存泄漏 希望读者们多多三连支持小编会继续更新你们的鼓励就是我前进的动力 继C语言初步学习了内存动态管理本篇将继续学习C部分更深入底层逻辑的内存管理
1.C/C内存分布回顾 程序中需要存储的数据局部数据、静态数据和全局数据、常量数据、动态申请数据
常量和可变常量的区别 经常很多人以为加了const的变量就是常量但其实不是的这叫可变常量例如 const int* ptr其实还是可以修改的它可以指向不同的常量整数但不能通过该指针修改所指向的值。 检查类型存储位置的小tips 看地址存放是否相近相近则存放在同一区域相差巨大则存放在不同区域
2.C内存管理
我们直到在堆上动态开辟空间需要使用mallocrealloc等函数不仅要保证前后类型一致还要断言空指针感觉还是太麻烦了所以在C使用了更简洁方便的动态开辟函数
2.1 内存申请
通过new和delete操作符进行动态内存管理
动态申请1个int类型的空间
//C
int* p1 (int*)malloc(sizeof(int));
free(p1);//C
int* p2 new int;
delete p2;动态申请存储10个int类型的数组
//C
int* p3 (int*)malloc(sizeof(int) * 10);
free(p3);//C
int* p4 new int[10];
delete[] p4;动态申请存储1个int类型的空间并初始化为10
int* p5 new int(10);
delete p5;动态申请数组并初始化多个元素
int* p6 new int[10] {1,2,3};
delete[] p6;访问开辟的数组元素
int* p4 new int[10];
cout p4[0] endl;
delete[] p4;对于指针 p4p4[i] 实际上等价于 *(p4 i)。也就是说p4[0] 表示访问 p4 所指向的内存位置即数组的第一个元素的值
那么new和delete存在的意义是什么 在C语言中malloc只完成了纯粹的开空间操作虽然calloc也能对空间初始化但是只能将所有元素初始化 在C中new能够初始化部分元素比如在链表里能够调用构造函数来完成初始化操作省去了写BuyNewnode函数的麻烦。delete相对于free会进行严格的类型检查确保释放的是new开辟的空间而且会调用析构函数 值得注意的是 申请和释放单个元素的空间使用new和delete操作符申请和释放连续的空间使用new[]和delete[]注意要匹配起来使用
2.2 operator new与operator delete函数
我们知道malloc是开空间new是通过开空间构造函数实现的那么new的开空间可以直接调用malloc吗答案是不可以的
首先我们要知道面向对象开空间失败喜欢抛异常而不是返回nullptr
malloc开无限大空间
malloc开空间没有显示任何错误难以发现
new开无限大空间 new开空间会在开空间失败后抛出异常用try...catch...捕获异常显示具体错误
/*
operator new该函数实际通过malloc来申请空间当malloc申请空间成功时直接返回申请空间失败
尝试执行空间不足应对措施如果改应对措施用户设置了则继续申请否则抛异常
*/
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
// try to allocate size bytes
void *p;
while ((p malloc(size)) 0)
if (_callnewh(size) 0)
{
// report no memory
// 如果申请内存失败了这里会抛出bad_alloc 类型异常
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}所以根据operator new的底层代码new的开空间错误是要抛异常的不能直接调用而是new先调用operator new然后operator new再调用malloc开空间。实际上malloc是被封装在了operator new里面的 对自定义类型进行操作时调试状态下转到反汇编可以发现有两条call指令一条调用operator new一条调用构造函数也能证实我们上面的说法operator delete也是同理
那么又延伸出另一个问题operator new和operator delete的调用顺序是怎么样的
假设类Stack需要开辟动态数组_arry容量_capacity大小_size
Stack* p1 new Stack;
delete p1;p1作为指针变量存放地址在栈上存储然后new的空间在堆上开辟_array又指向开辟的数组。如果按我们正常想的先调用operator delete释放堆空间那么_array指向的数组即使调用析构函数也找不到无法释放
因此我们可以整理出operator new和operator delete的调用顺序
调用operator new开辟空间调用构造函数调用析构函数调用operator delete释放空间
2.3 定位new表达式
class A
{
public:A(int a 0): _a(a){cout A(): this endl;}~A(){cout ~A(): this endl;}
private:int _a;
};
// 定位new/replacement new
int main()
{// p1现在指向的只不过是与A对象相同大小的一段空间还不能算是一个对象因为构造函数没有执行A* p1 (A*)malloc(sizeof(A));new(p1)A; // 注意如果A类的构造函数有参数时此处需要传参p1-~A();free(p1);A* p2 (A*)operator new(sizeof(A));new(p2)A(10);p2-~A();operator delete(p2);return 0;
}定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象这里p1p2只是个自定义类型无法调用构造函数所以要用定位new
其语法形式为 new (place_address) type或者new (place_address) type(initializer-list) place_address必须是一个指针initializer-list是类型的初始化列表 在实际应用中定位new一般用于池化技术也就是向内存申请一块内存池使用因为频繁的向内存申请堆太麻烦了所以申请一块内存池用于堆开辟空间
但是内存池的分配操作仅仅是对内存指针进行移动和管理它只负责提供一块可用的原始内存并没有内存初始化的操作 当使用 new 操作符来创建对象时它会完成两个主要步骤首先分配内存然后自动调用对象的构造函数对这块内存进行初始化。但内存池的分配操作只是完成了第一步即提供内存并没有触发构造函数调用的机制此时定位new的作用就体现出来了显式调用构造函数实现初始化操作 3.关于内存管理的常见知识点
3.1 malloc/free和new/delete的区别
malloc/free和new/delete的共同点是
都是从堆上申请空间并且需要用户手动释放
不同的地方是
malloc和free是函数new和delete是操作符malloc申请的空间不会初始化new可以初始化malloc申请空间时需要手动计算空间大小并传递new只需在其后跟上空间的类型即可 如果是多个对象[]中指定对象个数即可malloc的返回值为void*, 在使用时必须强转new不需要因为new后跟的是空间的类型malloc申请空间失败时返回的是NULL因此使用时必须判空new不需要但是new需要捕获异常申请自定义类型对象时malloc/free只会开辟空间不会调用构造函数与析构函数而new在申请空间后会调用构造函数完成对象的初始化delete在释放空间前会调用析构函数完成空间中资源的清理
3.2 内存泄漏
什么是内存泄漏 内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失而是应用程序分配某段内存后因为设计错误失去了对该段内存的控制因而造成了内存的浪费 如何检测内存泄漏?
在vs下可以使用windows操作系统提供的_CrtDumpMemoryLeaks() 函数进行简单检测该函数只报出了大概泄漏了多少个字节没有其他更准确的位置信息
int main()
{
int* p new int[10];
// 将该函数放在main函数之后每次程序退出的时候就会检测是否存在内存泄漏
_CrtDumpMemoryLeaks();
return 0;
}// 程序退出后在输出窗口中可以检测到泄漏了多少字节但是没有具体的位置
Detected memory leaks!
Dumping objects -
{79} normal block at 0x00EC5FB8, 40 bytes long.
Data: CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.因此写代码时一定要小心尤其是动态内存操作时一定要记着释放。但有些情况下总是防不胜防简单的可以采用上述方式快速定位下。如果工程比较大内存泄漏位置比较多不太好查时一般都是借助第三方内存泄漏检测工具处理的
在linux下内存泄漏检测 linux下几款内存泄漏检测工具 在windows下使用第三方工具 VLD工具说明 其他工具 内存泄漏工具比较
内存泄漏非常常见解决方案分为两种
事前预防型如智能指针等事后查错型如泄漏检测工具 希望读者们多多三连支持
小编会继续更新
你们的鼓励就是我前进的动力