C++内存管理

内存管理

电脑上的资源:CPU、内存、磁盘
CPU/GPU
GPU是简单的CPU,做简单运算,数量很多
内存中有许多区域:栈、堆、数据段/静态区、代码段/常量区

栈:局部变量
堆:动态开辟的
静态区:全局变量,静态变量
常量区:常量数据

分区域本质是他们的声明周期不同

C语言内存管理方式

malloc/calloc/realloc/free

void Test ()
{
// 1.malloc/calloc/realloc的区别是什么?
//malloc开空间不初始化
//calloc开空间又初始化
//realloc扩容
int* p2 = (int*)calloc(4, sizeof (int));
int* p3 = (int*)realloc(p2, sizeof(int)*10);
// 这里需要free(p2)吗?
//不需要,原地扩和异地扩
//原地扩,p2和p3指向同一块空间,在p2的后面开了一块空间,只需要释放p3即可
//异地扩,会把原来p2指向的内容拷贝到p3指向的新空间中,然后会自动free掉p2,所以只需要free p3
free(p3 );
}

C++ new和delete

C++通过new和delete进行操作内存的管理
new和delete都是操作符/关键字
申请和释放单个元素的空间new 和 delete操作符
申请和释放连续的空间,new [] 和 delete[]

new既开空间又调用构造函数(初始化)
delete既释放空间又调用析构函数(销毁)

  • new/delete操作内置类型

声明

int* p1 = new int;
//new一个int的对象,声明
int* p2 = new int[10];
//new 10 个int大小的空间
delete p1;
delete[] p2;

申请对象+初始化

int* p3 = new int(0);
//p3指向一个数据为0的空间
int* p4 = new int[10]{0};
//10个数据都初始化为0
int* p5 = new int[10]{1,2,3,4,5};
//前5个初始化,后5个为0
delete p3;
delete[] p4;
delete[] p5;
  • new/delete操作自定义类型
    C++对于内置类型malloc和free就够用,但是为了自定义类型才使用new/delete,因为他们自动调用构造和析构函数
A* p1 = new A;//默认构造
A* p2 = new A(1);//传参构造

delete p1;
delete p2;

A* p3 = new A(2,2);
//传多个参数构造

动态开辟的类类型的数组

//没有默认构造,显示(给值)构造的三种方式
A* p1 = new A(1);
A* p2 = new A(2,2);

1.有名对象
A aa1(1,1);//调用构造
A aa2(2,2);
A aa3(3,3);
A* p3 = new A[3]{aa1,aa2,aa3};//拷贝构造

2.匿名对象
A* p4 = new A[3]{A(1,1),A(2,2),A(3,3)};
// A aa = A(1,1) 本来是构造+拷贝构造
//被编译器优化为直接构造

3.隐式类型转换
A* p5 = new A[3]{{1,1},{2,2},{3,3}};
//A aa1 = {1,1}; 隐式类型转换为A类型再用临时对象拷贝构造aa1
//被编译器优化为直接构造

operator new和operator delete函数

operator new 和 operator delete 是系统提供的全局函数,new的底层是operator new申请空间,delete的底层是operator delete释放空间

operator new实际上也是通过malloc来申请空间的,申请空间成功就直接返回,失败就抛异常,需要用try,catch捕捉异常,operator delete通过free来释放空间

平时使用一般不会发生抛异常,如果申请大块内存会发生抛异常

1.申请大块空间
try
{
  void* p1 = new char[1024*1024*1024];
  cout << p1 << endl;
  void* p2 = new char[1024*1024*1024];
  cout << p2 << endl;
  void* p3 = new char[1024*1024*1024];
  cout << p3 << endl;
  //开三次大块空间,第一次会成功,后两次失败,抛异常
}
catch(const exception& e)
{
    //execption 库里面的一个异常的类型
    cout << e.what() << endl;
}
//打印
bad allocation
没有你需要的那么大的内存了

2. 调用的函数异常
void func()
{
   int n = 1;
   while(1)
   {
      void* p1 = new char(对象类型)[1024*1024](对象大小)
      cout << p1 << "->" << n << endl;
      //申请的次数太多
   }
}
int main()
{
   try
   {
     func();//函数异常
   }
   catch(const exception& e)
   {
     cout << e.what() << endl;
   }
}

new 调用operator new,operator new 调用构造函数和malloc,delete 调用operator delete, operator delete 调用析构函数和free

new和delete实现的原理

内置类型
new delete申请释放单个元素空间,new[] delete[]申请释放连续空间,new申请失败抛异常,malloc失败会返回NULL

自定义类型
new
1.调用operator new完成空间申请
2.在申请空间的基础上完成对象构造初始化
delete
1.调用析构完成资源的清理工作
2.调用operator delete完成对象空间释放的工作

定位new表达式(placement-new)

定位new

A* p1 = new A(1);
delete p1;

A* p2 = (A*)operator new(sizeof(A));
//开空间
new(p2)A(1);
//构造要定位new 初始化
p2->~A();
//析构可以显示调用
operator delete(p2);
//释放空间

在平时的场景下根本用不到定位new,而在特殊场景内存池时要用到,因为内存池分配出的空间没有初始化,需要我们手动初始化,就要显示调用构造函数

比如某个业务模块需要高频使用,而每次在堆上申请空间需要等待,所以创建一个内存池给你这个业务专门使用,就能提高效率

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值