C++中的内存分配和管理

1. 数据段(Data Segment)

1) 初始化数据段存储已初始化的全局变量和静态变量包括全局/静态 int、char、数组、结构体等)。(在函数外声明定义或static修饰)

这些变量的初始值在编译时确定,并在程序加载时直接写入内存。

示例:  int global_var = 42;          // 存储在 .data 段

            static int static_var = 100;            // 存储在 .data 段

(2) 未初始化数据段(.bss段,Block Started by Symbol)

存储未初始化的全局变量和静态变量(或初始化为 0 的变量)。

程序加载时,操作系统会将该段内存全部初始化为 0。

示例:  int global_uninit;           // 存储在 .bss 段(默认 0)

           static int static_uninit;           // 存储在 .bss 段(默认 0)

(3) 只读数据段(.rodata 段)

     存储常量数据,如字符串常量(char a[]=”abcd”,a就是字符串常量)、const全局变量等。

     该段内存是只读的,修改会导致段错误。

段错误(Segmentation Fault,简称 Segfault): 是程序运行时的一种常见错误,通常是由于程序试图访问未被允许访问的内存区域即“越界访问”)导致的。操作系统会检测到这种非法操作,并强制终止程序,同时生成“段错误”信息。(例如将字符串常量a重新赋值,会发生段错误,因为常量数据不能修改)

2. 代码段

1. 代码段的作用 存放机器指令:编译后的二进制代码(CPU 直接执行的指令)。

只读(Read-Only):防止程序运行时修改自身代码,提高安全性和稳定性。

共享访问:多个进程可以共享同一份代码段(如动态链接库 DLL/so)

2. 代码段存储的内容

内容                                   说明                                

函数代码              所有函数(如 main()、自定义函数)的机器指令。                                               

程序入口点          程序启动时执行的第一个指令(如 _start或main 的地址)。                             

跳转表                  用于动态链接的函数跳转地址(如 PLT, Procedure Linkage Table)。

常量代码数据        某些编译器会将部分常量数据(char a[]=”abcd”,*a就是字符串放在代码段)                                       ( 如跳转表)放在代码段附近。        

3. 代码段的特点  

特性                                                            说明                                                    

 只读(Read-Only)                  修改代码段会导致段错误(Segmentation Fault)。                       固定大小                                   在编译时确定,运行时不会动态增长。                                         共享性                                      多个进程可以共享相同的代码段(如动态库)。                               位置独立代码(PIC)              某些代码段可以加载到任意内存地址执行(用于动态库)。

3.malloc ,operator new,new的区别

malloc = operator new+失败抛异常

new = operator new+调用构造函数初始化

class Date3
{
public:
	Date3(int year = 1, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "Date2(int year = 1, int month = 1, int day = 1" << endl;
	}
	~Date3()
	{
		cout << "~Date3()" << endl;
	}
	void print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year = 1;
	int _month = 1;
	int _day = 1;
};
void test2()
{
	// new==opertaor new+调用构造函数
	cout << "测试operator new:" << endl;
	Date3* p2 = (Date3*)operator new(sizeof(Date3));   //   只开辟空间
	p2->print();
	cout << "测试new:" << endl;
	new(p2)Date3();     //     用定位new  初始化 
	p2->print();
	delete p2;



	//  operator new  与  malloc   的区别  :  使用的方式一样,处理错的方式不一样        (也是new与malloc 差异的一部分)
	size_t size = 2;
	void* p3 = malloc(size * 1024 * 1024 * 1024*100);     // 失败返回0 --> 00000000000   开辟空间失败
	cout << p3 << endl;
	free(p3);
	p3 = nullptr;



	//opeerator new
	try
	{
		void* p4 = operator new(size * 1024 * 1024 * 1024*0);   //    失败抛异常  (面对对象处理错的方式)
		cout << p4 << endl;
		free(p4);
		p4 = nullptr;
	}
	catch(exception&e)
	{
		cout << e.what() << endl;
	}
}

结果:

测试operator new:
-842150451--842150451--842150451   //  随机值,没有调用构造函数
测试new:
Date2(int year = 1, int month = 1, int day = 1
1-1-1
~Date3()     //  delete会调用析构函数   //而free不会
0000000000000000    //  malloc开辟空间失败但正常返回000000000000 ,没有抛异常
000001B2F1C97EE0    //  返回了开辟空间的首地址
bad allocation     //  operator 抛异常

4. malloc / free 和 new / delete 的比较

 malloc / free 和 new / delete 的共同点是:都是从堆上申请空间,并且需要用户手动释放

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

5.内存泄漏

什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不能再使用该内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值