C++ 编译的程序占用内存:
- 栈区:执行函数时,函数内局部变量的存储单元在栈上创建,变量的声明周期结束后,这些内存单元会自动被释放。栈内存分配运算内置于处理器的指令集,效率高,但是分配的内存有限。
- 堆区:动态内存分配,程序在运行时使用 malloc 或者 new 申请任意大小内存,由程序员负责在何时使用 free 或者 delete 释放内存。动态内存的生命周期由程序员决定,使用灵活,但是如果在堆上分配了空间,就有责任去回收它,否则运行的程序会出现内存泄漏,频繁的分配和释放不同大小的堆空间会产生内存碎片。
- 静态存储区:内存在程序编译时就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量、static 变量 就在静态存储区分配内存。
- 常量区:存放常量字符串,程序结束后由系统释放。
- 代码区:存放函数体(类成员将函数和全局区)的二进制代码
使用 new / delete 直接管理内存:
new : 为对象分配空间并返回一个指向该对象的指针
delete:接受一个动态对象的指针,销毁该对象,并释放与之关联的内存
注意事项:
1、new / delete 需要搭配使用,用 new 申请了一块内存,就必须用 delete 释放该内存。否则会产生内存泄漏。
int main()
{
int* pi = new int(5); // 用 new 申请内存
delete pi; // delete 释放该内存
return 0;
}
2、尽量使用 “值初始化” : 用 () 来初始化
int main()
{
int* pi = new int; // 返回一个 int型随机值
int* pi2 = new int(); // pi2 的值初始化为 0
int* pi3 = new int(10); // pi3 的值初始化为 10
return 0;
}
3、指针 delete 后内存被释放,内存中的数据被销毁,此内存不该再被访问。但是 delete 后的指针仍然保留着已经释放的动态内存的地址。建议指针 delete 后,赋值为 nullptr。
int main()
{
int* pi = new int(123);
cout << *pi << "\t" << pi << endl;
delete pi; // 内存被释放,内存中数据被销毁,但是 pi 仍存着这块内存的地址
cout << *pi << "\t" << pi << endl;
pi = nullptr; // 指针地址指空,后续则不能再通过 pi 访问到之前分配的内存
cout << *pi << "\t" << pi << endl;
return 0;
}
4、指针指向 nullptr 后,再去 delete 不会调用到析构函数。因为此时 指针不再指向分配的内存的地址,通过此指针系统不知道应该回收哪块内存。所以应该先 delete 指针,再去将指针置空。
class A
{
public:
A()
{
cout << "A()" << endl;
}
~A()
{
cout << "~A()" << endl;
}
};
int main()
{
A* pa1 = new A();
pa1 = nullptr;
delete pa1; // 不会调用析构函数,但是应该回收的内存未被回收
A* pa2 = new A();
delete pa2;
delete pa2; // 会多次调用析构函数,可能产生异常
A* pa3 = new A();
delete pa3;
pa3 = nullptr; // 内存已被回收,后续再通过 pa3 访问不到原内存
return 0;
}
5、只有通过 new 出来的地址,才需要 delete 释放对应的内存。对栈上分配的对象取到的地址,不能通过 delete 释放该内存。
int main()
{
int i = 10;
int* pi = &i;
delete pi; // 错误,pi 指向的是对象 i 在栈上分配的内存对应的地址,不可通过 delete 释放。
return 0;
}
6、同一块内存,不能多次释放
int main()
{
int* p1 = new int(123);
int* p2 = p1; // p2指向和 p1 同一块内存
delete p1;
delete p2; // 错误,p2 指向的内存已经在 delete p1 时被释放。
return 0;
}
7、用 auto 来 new 一个对象时,若传入的是指针,则返回指针的指针 (诡异的写法,尽量避免)
int main()
{
int* p = new int(123);
cout << p << endl;
cout << *p << endl;
auto pp = new auto(p); // pp 为 int** 型指针
// 相当于
// int** pp = new int*(p) ;
cout << pp << endl;
cout << *pp << endl;
cout << **pp << endl;
return 0;
}
网友评论