文章目录
- 1. C/C++内存分布
- 2. C语言中动态内存管理方式:malloc/calloc/realloc/free
- 3.C++内存管理方式new/delete
- 3.1 new/delete操作内置类型
- 3.2 new/delete操作自定义类型
- 4. operator new和operator delete函数(重点)
- 4.1底层原理
- 5.malloc/free和new/delete的区别
- 6. 定位new表达式(placement-new)
1. C/C++内存分布
int globalvar = 1;
static int staticGlobalvar = 1;
void Test()
{
static int staticVar = 1;
int localvar = 1;
int num[10] = { 1,2,3,4 };
char char2[] = "abcd";
const char* pChar3 = "abcd";
int* ptr1 = (int*)malloc(sizeof(int) * 4);
int* ptr2 = (int*)malloc(4, sizeof(int));
int* ptr3 = (int*)relloc(ptr2, sizeof(int) * 4);
free(ptr1);
free(ptr3);
}
- 选项:A. 栈 B.堆 C.数据段(静态区) D.代码段(常量区)
- globalvar:____ - staticGlobalar:_____ -staticVar:______
- localVar:_____ - num1:____
- char2:_____ - *char2:_____
- pChar3:____ - *pChar3:____
- ptr1:____ - *ptr1:_____
C C C A A A A A D A B - sizeof(num1)=____ - sizeof(char2)=____ - strlen(char2)=______
- sizeof(pChar3)=____ - strlen(pChar3)=____ - sizeof(ptr1)=______
40; 5; 4(遇见\0截止); 4/8(是一个指针,和后面指向的东西没有关系,32位4,64位8); 4(有效字符的个数); 4/8(指针)
- 栈又叫堆栈–非静态局部变量/函数参数/返回值等,栈是向下增长的
- 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可以使用系统接口创建共享共享内存,做进程间通信。
- 堆:用于程序运行时的动态内存分配,堆可以是向上增长的。
- 数据段:存储全局数据和静态数据
- 代码段:可执行的代码/只读常量
2. C语言中动态内存管理方式:malloc/calloc/realloc/free
void Test()
{
int* p1 = (int*)malloc(size(int));
free(p1);
//1.malloc/calloc/realloc的区别?
int* p2 = (int*)calloc(4, sizeof(int));
int* p3 = (int*)realloc(p2, sizeof(int) * 10);
//这里需要free(p2)嘛?
free(p3);
}
3.C++内存管理方式new/delete
不推荐malloc和free,C++的new/delete更简洁,对内置类型差别不大,自定义类型会调用构造函数和析构函数。
3.1 new/delete操作内置类型
int main()
{
int* p1 = new int;//new不用检查,不会初始化。
int* p2 = (int*)malloc(sizeof(int));//要去强转,VS2019检查严格
if (p2 == nullptr)
{
perror("malloc fail");
}
return 0;
}
int* p3=new int(0);//初始化为0
delete p3;
int* p4=new int[10];//申请了10个int的数组
delete[] p4;
int* p5=new int[10]{1,2,3,4};//初始化
new可以帮助初始化
void Test()
{
//动态申请一个int类型空间
int* ptr4 = new int;
//动态申请一个int类型的空间并初始化为10
int* ptr5 = new int(10);
//动态申请10个int类型的空间
int* ptr6 = new int[3];
delete ptr4;
delete ptr5;
delete[] ptr6;
}
new一定要去匹配使用,不要交叉,否则结果不确定。
3.2 new/delete操作自定义类型
单个对象调单次构造函数,多个对象调多次构造函数。delete调析构函数
根本上而言,C和C++内存管理用一套模式
4. operator new和operator delete函数(重点)
4.1底层原理
库里面的全局函数operator new和operator delete,不是运算符重载。本质是malloc和free的封装。
new和delete是用户进行动态内存申请和释放的操作符,operator new和operator delete是全局函数。new在底层调用delete new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间
int main()
{
//出错机制不同
//失败以后抛异常
int* p1=(int*)operator new(sizeof(int*));
//失败返回空nullptr
int* p2 = (int*)malloc(sizeof(int*));
if (p2 == nullptr)
{
perror("malloc fail");
}
//面向对象的语言处理错误时基本上使用抛异常。
//new 1.申请空间 operator new,封装malloc 2.调用构造函数
A* p3 = new A;//调用operator new
//delete需先调用析构函数,在使用p3指向的空间
delete p3;
//申请空间 operator new[]->operator new->封装malloc
//调用10次构造函数
A* p6 = new A[10];
delete[] p6;
//delete需先调用10次析构函数,在使用operator delete[] p6指向的空间
int* p7 = new int[10];
free(p7);
//不会造成内存泄露,因为针对的是内置类型,不会报错
A* p8 = new A;
free(p8);
//不会报错。operator delete->free,只是没有调用析构函数,少调不会报错
return 0;
}
class Stack
{
public:
Stack()
{
cout << "Stack()" << endl;
_a = new int[4];
_top = 0;
_capacity = 4;
}
private:
int* _a;
int _top;
int _capacity;
};
Stack st;
//调用构造,会调用析构
Stack* pst = new Stack;//指针,内置类型,不调用析构
//pst:4个字节,是个指针。new的机制:开空间,12个字节,开在堆上面,再调用构造函数,再去堆上开16个字节,也就是4个整型
delete pst;
- 先调用析构函数,完成栈指向的资源的清理
- 调用operator delete(pst),释放结构对象的空间。
- 由于底层的实现有关联交叉,不匹配使用可能有问题可能没有问题,因此最好要匹配使用
A* p9=new A[10];
free(p9);//报错
delete p9;//报错
delete[] p9;//没有问题
了解其底层机制
5.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在释放空间前会调用析构函数完成空间中资源的清理。
用法+底层原理
int main()
{
size_t size = 0;
while (1)
{
int* p1 = (int*)malloc(1024 * 1024 * 4);
if (p1 == nullptr)
{
break;
}
size += 1024 *1024* 4;
cout << p1 << endl;
}
cout << size << endl;
cout << size/1024/1024 << "MB"<<endl;
}
C++出错抛异常。
int main()
{
size_t size = 0;
try
{
while (1)
{
int* p1 = new int[1024 * 1024];
if (p1 == nullptr)
{
break;
}
size += 1024 * 1024 * 4;
cout << p1 << endl;
}
}
catch (const exception& e)
{
cout << e.what()<< endl;
}
cout << size << endl;
cout << size/1024/1024 << "MB"<<endl;
}
bad allocation:申请内存失败。
6. 定位new表达式(placement-new)
定位new表达式是在一分配的原始内存空间中调用构造函数初始化一个对象。
使用格式:
new(place_address)type或者new(place_address)type(initializer-list)
place_address必须是一个指针,initializer-list是类型的初始化列表
int main()
{
A aa;
A* p1 = (A*)malloc(sizeof(A));
if (p1 == nullptr)
{
perror("malloc fail");
}//构造函数不能显式调用
//对一块已有的空间初始化——定位new
//new(p1)A;
//定位new
new(p1)A(1);//需要有参数
//调用析构函数:
p1->~A();
free(p1);
return 0;
}
//改进malloc
A* p2 = new A;
delete p2;
有一类场景需要这个malloc,需要提升性能,内存从内存池进行申请