c/c++中程序内存区域划分
- 这几个区域堆是很大
- 从图里面看栈和堆差不多大,实际上不是。栈很小,linux下一般8M,所以递归调用深度太深,会导致栈溢出
- 数据段和代码段也没有多大,因为没有多少数据
malloc、calloc、realloc的区别
calloc等价于malloc+memset(0)即开空间+初始化
realloc是对malloc或calloc的空间进行扩容
void Test ()
{
int* p1 = (int*) malloc(sizeof(int));
free(p1);
int* p2 = (int*)calloc(4, sizeof (int));
int* p3 = (int*)realloc(p2, sizeof(int)*10);
// 这里需要free(p2)吗?
free(p3 );
}
C++内存管理
一定要匹配使用–malloc和free,new和delete,否则可能会崩溃,C++建议尽量使用new和delete
- C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理
动态内存malloc / new、free / delete的区别–重点
//自定义类型
class A
{
public:
A(int a = 0)
: _a(a)
{
cout << "A()" << this << endl;
}
A(const A& a)
{
cout << "A(const A& a)" << this << endl;
}
A& operator=(const A& a)
{
cout << "A& operator=(const A& a)" << this << endl;
return *this;
}
~A()
{
cout << "~A():" << this << endl;
}
private:
int _a;
};
int main()
{
// 内置类型,用malloc和new没什么区别
int* p1 = (int*)malloc(sizeof(int) * 10);
int* p2 = new int[10];
free(p1);
delete[] p2;
// 自定义类型,用malloc/free和new/delete有区别
//有区别,new/delete还会调用构造函数和析构函数,malloc和free是库函数,new和delete是操作符
A* p3 = (A*)malloc(sizeof(A));
A* p4 = new A;
A* p5 = new A(10);//用带参构造函数
A* p6 = new A[5];//用默认构造函数
free(p3);
delete p4;
delete p5;
delete[] p6;
return 0;
}
}
区别总结
在链表中使用new / delete比malloc / free更简洁
struct ListNode
{
ListNode* _next;
ListNode* _prev;
int _val;
//C++调用构造函数
ListNode(int val)
:_next(nullptr)
, _prev(nullptr)
, _val(val)
{}
};
//c
ListNode* BuyListNode(int val)
{
ListNode* node = (ListNode*)malloc(sizeof(ListNode));
node->_val = val;
node->_prev = nullptr;
node->_next = nullptr;
return node;
}
int main()
{
// c
ListNode* cur_c = BuyListNode(1);
// cpp
ListNode* cur_cpp = new ListNode(1);
return 0;
}
mallloc和new开辟空间失败
- malloc会输出malloc fail,而new不输出但是会抛出异常
int main()
{
// malloc失败,返回NULL
char* p1 = (char*)malloc((size_t)2*1024*1024*1024);
if (p1 == NULL)
{
printf("malloc fail\n");
}
else
{
printf("malloc success:%p\n", p1);
}
// new跟malloc不一样,申请空间失败了,抛异常
try
{
char* p2 = new char[0x7fffffff]; // 出错,抛异常,调到捕获异常的位置
printf("xxxx");
}
catch (const exception& e)
{
cout << e.what() << endl;
}
return 0;
}
operator new/delete–很少使用
new和delete的过程–重点
显示调用构造函数初始化
使用:空间是内存池申请来的。
struct ListNode
{
int val;
struct ListNode* next;
static int _count;
ListNode(int x)
:val(x)
, next(nullptr)
{
cout << "ListNode()" << endl;
}
~ListNode()
{
cout << "~ListNode()" << endl;
}
}
int main()
{
// 构造函数自动调用的两种方式
//1定义对象
ListNode node(1);
//2、new
ListNode* p = new ListNode(2);
ListNode* n1 = (ListNode*)malloc(sizeof(ListNode));
//显示对一块空间调用构造函数初始化
new(n1) ListNode(3);
//显示调用析构函数
n1->~ListNode();
free(n1);
return 0;
}
运用
class A
{
public:
A(int a = 0)
: _a(a)
{
cout << "A()" << this << endl;
}
A(const A& a)
{
cout << "A(const A& a)" << this << endl;
}
A& operator=(const A& a)
{
cout << "A& operator=(const A& a)" << this << endl;
return *this;
}
~A()
{
cout << "~A():" << this << endl;
}
private:
int _a;
};
int main()
{
A a[5];
cout << endl;
// 复制一份a数组到另外一块空间b--代价就是构造+赋值
//拷贝构造针对单个对象,针对数组不行
A* pb1 = new A[5];
for (int i = 0; i < 5; ++i)
{
pb1[i] = a[i];
}
cout << endl;
// 能不能直接拷贝构造
A* pb2 = (A*)malloc(sizeof(A) * 5);
for (int i = 0; i < 5; ++i)
{
new(pb2 + i)A(a[i]);
}
return 0;
}
内存泄漏
内存泄漏:在堆上申请空间,我们不用了也没有释放,就存在内存泄漏
int main()
{
char* p = new char[1024 * 1024 * 1024];
return 0;
}
开辟空间
要想开辟2个G,32位编译器下–虚拟进程地址空间只有4个G的空间一般是不能开2个G,所以把编译器调为64位编译器就能开辟了