内存管理
C/C++ 内存分布
- 静态区(数据段)
- 全局变量:在整个程序运行期间都存在的变量,包括没有显式声明为
static
的全局变量。 - 静态局部变量:在函数内部声明为
static
的变量。它们在函数首次调用时初始化,并在程序整个运行期间保持其值。 - 静态全局变量:在文件作用域中声明为
static
的变量。它们只在声明它的文件中可见,并在整个程序运行期间存在。
- 全局变量:在整个程序运行期间都存在的变量,包括没有显式声明为
- 常亮区(代码段)
- 字符串字面量:如
"Hello"
这样的字符串字面量存储在常量区,不可修改。 - 常量数据:使用
const
关键字声明且初始化的常量数据也通常存放在常量区。
- 字符串字面量:如
- 栈
- 局部自动变量:在函数内部声明的非静态局部变量,随函数调用入栈和出栈。
- 函数调用的参数:传递给函数的参数通常存储在栈中。
- 局部数组和结构体:在函数内部声明的数组和结构体也会存储在栈中。
- 堆
- 动态分配的内存:通过
malloc()
,calloc()
,realloc()
等函数申请的内存存储在堆中。这些内存需要通过free()
释放以避免内存泄漏。
- 动态分配的内存:通过
【说明】
- 生命周期:数据的生命周期是关键因素。全局的静态数据具有较长的生命周期,存储在静态区;局部自动变量和函数参数生命周期较短,存储在栈中。
- 可变性:常量数据存储常量区,因为它们不可更改。
- 动态需求:堆用于满足运行时动态大小的需求,如动态数组或链表节点。
C语言中动态内存管理方式
malloc
:申请一块指定大小的连续内存区域,返回指向这块内存的指针。
calloc
:同malloc
并将内容初始化为0
.
realloc
:对已分配内存块改变大小,如果原内存块无法调整大小,realloc
尝试分配一块新内存,并复制原有内容。
free
:释放malloc
、calloc
、realloc
申请的内存,防止内存泄漏。
new/delete操作内置类型
注意:申请和释放单个元素的空间,使用
new
和delete
操作符,申请和释放连续的空间,使用new[]
和delete[]
,匹配使用。
既然已经有了
malloc
和free
,new
和delete
的意义何在?
- 对于上面内置类型,他们效果是一样的。
- 对于自定义类型,效果就不一样。malloc只申请空间。new申请空间+构造函数初始化
注意:在申请自定义类型的空间时,
new
会调用构造函数,delete
会调用析构函数,而malloc
与free
不会。
new和delete操作自定义类型
new
的原理
- 调用
operator new
函数申请空间。- 在申请的空间上执行构造函数,完成对象的构造。
delete
的原理
- 在空间上执行析构函数,完成对象中资源的清理工作。
- 调用
operator delete
函数释放对象的空间。new T[N]
的原理
- 调用
operator new[]
函数,在operator new[]
中实际调用operator new
函数完成N
个对象空间的申请。- 在申请的空间上执行
N
次构造函数。delete[]
的原理
- 在释放的对象空间上执行
N
次析构函数,完成N
个对象中资源的清理。- 调用
operator delete[]
释放空间,实际在operator delete[]
中调用operator delete
来释放空间。
typedef struct LinstNode_C {
int _val;
struct ListNode* _next;
struct ListNode* _prve;
}Node;
Node* Init(int x) {
Node* node = (Node*)malloc(sizeof(Node) * x);
node->_val = x;
node->_prve = NULL;
node->_next = NULL;
return node;
}
void Destory(Node* node){
// ……
}
typedef struct ListNode_CPP {
int _val;
struct ListNode_CPP* _next; // C++兼容c的用法
ListNode_CPP* _prve; // 升级版struct 更方便
ListNode_CPP(int x = 0)
:_val(x)
,_prve(nullptr)
,_next(nullptr)
{
cout << "Init()" << endl;
}
~ListNode_CPP() {
cout << "~delete()" << _val << endl;
}
}Node_cpp;
Node* d1 = (Node*)malloc(sizeof(Node));
Node_cpp* d2 = new Node_cpp(5);
Node_cpp* d3 = new Node_cpp[5];
delete d2;
delete[] d3; // 调用相应空间个数的析构函数
new/delete操作内置类型
new
和delete
是用户进行动态内存申请和释放的操作符,operator new
和operator delete
是系统提供的全局函数,new
在底层调用operator new
全局函数来申请空间,delete
在底层通过operator delete
全局函数来释放空间。
size_t size = 2;
void* p4 = malloc(size * 1024 * 1024 * 1024 * 1024);
cout << p4 << endl; // 溢出返回0
// free(p4);
try {
void* p5 = operator new(size * 1024 * 1024 * 1024 * 1024);
cout << p5 << endl; // 溢出报错
//operator delete(p5);
}
catch(exception& e){
cout << e.what() << endl;
}
operator new
和malloc
的区别是什么?结论:使用方式都一样,处理错误的方式不一样
总结:
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
在释放空间前会调用析构函数完成空间中资源的释放。
内存泄漏
标签:Node,malloc,管理,C++,内存,operator,new,delete From: https://www.cnblogs.com/chu0522/p/18284605什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
内存泄漏的危害: 长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等,出现内存泄漏会导致响应越老越慢,最终卡死。