首页 > 系统相关 >C++内存管理

C++内存管理

时间:2024-07-04 20:20:36浏览次数:15  
标签:Node malloc 管理 C++ 内存 operator new delete

内存管理

C/C++ 内存分布

  1. 静态区(数据段)
    • 全局变量:在整个程序运行期间都存在的变量,包括没有显式声明为static的全局变量。
    • 静态局部变量:在函数内部声明为static的变量。它们在函数首次调用时初始化,并在程序整个运行期间保持其值。
    • 静态全局变量:在文件作用域中声明为static的变量。它们只在声明它的文件中可见,并在整个程序运行期间存在。
  2. 常亮区(代码段)
    • 字符串字面量:如"Hello"这样的字符串字面量存储在常量区,不可修改。
    • 常量数据:使用const关键字声明且初始化的常量数据也通常存放在常量区。
    • 局部自动变量:在函数内部声明的非静态局部变量,随函数调用入栈和出栈。
    • 函数调用的参数:传递给函数的参数通常存储在栈中。
    • 局部数组和结构体:在函数内部声明的数组和结构体也会存储在栈中。
    • 动态分配的内存:通过malloc()calloc()realloc()等函数申请的内存存储在堆中。这些内存需要通过free()释放以避免内存泄漏。

【说明】

  • 生命周期:数据的生命周期是关键因素。全局的静态数据具有较长的生命周期,存储在静态区;局部自动变量和函数参数生命周期较短,存储在栈中。
  • 可变性:常量数据存储常量区,因为它们不可更改。
  • 动态需求:堆用于满足运行时动态大小的需求,如动态数组或链表节点。

image-20240704110919552

image-20240704111000518

C语言中动态内存管理方式

malloc:申请一块指定大小的连续内存区域,返回指向这块内存的指针。

calloc:同malloc并将内容初始化为0.

realloc:对已分配内存块改变大小,如果原内存块无法调整大小,realloc尝试分配一块新内存,并复制原有内容。

free:释放malloccallocrealloc申请的内存,防止内存泄漏。

image-20240704133050517

new/delete操作内置类型

image-20240704133638511

注意:申请和释放单个元素的空间,使用newdelete操作符,申请和释放连续的空间,使用new[]delete[],匹配使用。

image-20240704134122978

既然已经有了mallocfreenewdelete的意义何在?

  1. 对于上面内置类型,他们效果是一样的。
  2. 对于自定义类型,效果就不一样。malloc只申请空间。new申请空间+构造函数初始化

注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而mallocfree不会。

new和delete操作自定义类型

  • new的原理
    1. 调用operator new函数申请空间。
    2. 在申请的空间上执行构造函数,完成对象的构造。
  • delete的原理
    1. 在空间上执行析构函数,完成对象中资源的清理工作。
    2. 调用operator delete函数释放对象的空间。
  • new T[N]的原理
    1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请。
    2. 在申请的空间上执行N次构造函数。
  • delete[]的原理
    1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理。
    2. 调用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操作内置类型

newdelete是用户进行动态内存申请和释放的操作符,operator newoperator 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 newmalloc的区别是什么?结论:使用方式都一样,处理错误的方式不一样

总结:mallocfree、和newdelete的区别
malloc/freenew/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。不同的地方是:

  1. mallocfree是函数,newdelete是操作符
  2. malloc申请的空间不会初始化,new可以初始化
  3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可,如果是多个对象,[]中指定对象个数即可
  4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型
  5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常
  6. 申请自定义类型对象时,mallocfree只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的释放。

内存泄漏

什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。

内存泄漏的危害: 长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等,出现内存泄漏会导致响应越老越慢,最终卡死。

标签:Node,malloc,管理,C++,内存,operator,new,delete
From: https://www.cnblogs.com/chu0522/p/18284605

相关文章