C++(初阶)(六)——内存管理

内存管理

  • 内存管理
    • C/C++**内存分布
    • C语言中动态内存管理方式
    • C++内存管理方式
      • new/delete操作内置类型
      • new和delete操作自定义类型
      • new和malloc
      • operator new与operator delete
      • new和delete的实现原理
        • 内置类型
        • 自定义类型

C/C++**内存分布

int globalVar = 1;
static int staticGlobalVar = 1;
void Test() 
{ 
	static int staticVar = 1; 
	int localVar = 1; 
	int num1[10] = { 1, 2, 3, 4 }; 
	
    char char2[] = "abcd"; 
	const char* pChar3 = "abcd"; 
	int* ptr1 = (int*)malloc(sizeof(int) * 4); 
	int* ptr2 = (int*)calloc(4, sizeof(int)); 
	int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
    free(ptr1); 
    free(ptr3); 
}
选择题:
选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区) 

globalVar在哪里?(C)	
staticGlobalVar在哪里?(C)	全局,生命周期全局
staticVar在哪里?(C)		局部,生命周期全局
localVar在哪里?(A)
num1在哪里?(A)				数组名,数组/数组首元素地址,局部变量,存在栈中

    
char2在哪里?(A)	是一个局部的数组,
*char2在哪里? (A)	是指向首元素本身的,在栈中
pChar3在哪里?(A)	局部变量
*pChar3在哪里? (D)	const修饰指针变量
ptr1在哪里?(A)		局部变量的指针
*ptr1在哪里?(B)	动态开辟mallco(),需要手动释放

栈,堆,数据段(静态区) ,代码段(常量区)

栈是向下生长的,堆是向上生长的

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

void Test () 
{
	// 1.malloc/calloc/realloc的区别是什么? 
	int* p2 = (int*)calloc(4, sizeof (int)); 
    int* p3 = (int*)realloc(p2, sizeof(int)*10);  
	
	//2,这里需要free(p2)吗?
	free(p3 ); 
}

1,malloc/calloc/realloc的区别?

calloc会初始化为0,realloc会对空间扩容,原地扩容,异地扩容(程序在堆区开辟相应大小扩容,如果大

小不够,在另一个地方开辟总大小的空间,将内容拷贝,释放旧空间)

三者开辟的空间可以通过free释放。

2,在C语言中,使用realloc重新分配内存时,其行为决定了是否需要手动释放原指针:

  1. realloc成功时的两种情况

    • 原地扩展:若原内存块后方有足够空间,realloc会直接扩展内存,返回的指针p3与原指针p2相同。此时只需free(p3)即可,原指针p2已失效,无需操作。
    • 新内存块:若无法原地扩展,realloc会分配新内存、复制数据,并自动释放原内存块。此时p2指向的内存已被释放,若再free(p2)会导致双重释放(Undefined Behavior)。
  2. realloc失败时

    • 返回NULL,此时原指针p2仍有效。若直接free(p3)(即free(NULL),无害但无操作),会导致p2内存泄漏。正确做法是检查返回值,若失败则保留并处理p2

但是最好在此处判断一下realloc是否成功,如果不成功则还是需要手动释放,但是一般情况下realloc是不会失败的

void Test() {
    int *p2 = (int*)calloc(4, sizeof(int));
    int *p3 = (int*)realloc(p2, sizeof(int)*10);
    
    // realloc失败时,p3为NULL,此时p2仍有效
    if (p3 == NULL) {
        free(p2); //处理失败情况,释放原内存
        return;
    }
    
    free(p3); //成功时只需释放新指针
}

C++内存管理方式

new/delete操作内置类型

申请和释放单个元素的空间,使用new和delete操作符

申请和释放连续的空间,使用new[]delete[]

注意:匹配起来使用。

void Test() 
{
	// 动态申请一个int类型的空间,默认不会初始化(有些环境也可能会)
	int* ptr1 = new int;
	// 动态申请一个int类型的空间并初始化为10
	int* ptr2 = new int(10);
    
    // 动态申请10个int类型的空间
    int* ptr3 = new int[3];
    int* ptr3 = new int[4]{1,2,3,4};
    
    delete ptr1;
    delete ptr2;
    
    delete[] ptr3;
}

比如使用 char* p = new char[100]申请一段内存,然后使用delete p释放,有什么问题?( )

不会有内存泄露,对于内置类型,程序不会崩溃,但不建议这样使用

编译不会报错,建议针对数组释放使用delete[],如果是自定义类型,不使用方括号就会运行时错误

new和delete操作自定义类型

class A 
{
public: 
	A(int a = 0) 
	: _a(a) 
	{ 
		cout << "A():" << this << endl; 
	}
	~A() 
	{ 
		cout << "~A():" << this << endl; 
	} 
private:
int _a; };
int main() 
{ 
	// new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间 还会调用构造函数和析构函数 
	A* p1 = (A*)malloc(sizeof(A)); 
	A* p2 = new A(1); 
	free(p1); 
	delete p2; 
	
    // 内置类型是几乎是一样的 
	int* p3 = (int*)malloc(sizeof(int)); // C 
	int* p4 = new int; 
    free(p3); 
	delete p4;
    
    A* p5 = (A*)malloc(sizeof(A)*10); 
    A* p6 = new A[10]; 
    free(p5); 
    delete[] p6; 
    
    return 0; 
}

在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会。

new和malloc

处理错误方式不同:

malloc失败是返回空

new失败的机制是抛异常,如果直到main函数也没有捕获(使用try和catch),会直接报错

#include
using namespace std;

int main()
{
	size_t x = 0;
	int* ptr = nullptr;
	do
	{
		//ptr = (int*)malloc(10 * 1024 * 1024);
		if (ptr)
			x += 10 * 1024 * 1024;
		cout << ptr << endl;

	} while (ptr);

	cout << x << endl;
	cout << x / (1024 * 1024) << endl;

	return 0;
}

C++(初阶)(六)——内存管理_第1张图片
C++(初阶)(六)——内存管理_第2张图片

operator new与operator delete

两个全局的库函数

new和delete是用户进行动态内存申请和释放的操作符**,**operator new和operator delete是

系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过

operator delete全局函数来释放空间。

使用operator new封装malloc,实现开辟空间失败时,抛出异常,而非返回空给出错误码

通过上述两个全局函数的实现知道,operator new实际也是通过malloc来申请空间,如果

malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施

就继续申请,否则就抛异常。operator delete最终是通过free来释放空间的。

new和delete的实现原理

内置类型

在申请内置类型的空间时,new和malloc,delete和free的语法基本类似,不同的地方是:

1,new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间。

2,new在申请空间失败时会抛异常,malloc会返回NULL。

自定义类型

new的原理

1,调用operator new函数申请空间。

2,在申请的空间上执行构造函数,完成对象的构造。

operator delete: 该函数最终是通过free来释放空间的

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来释放空间

你可能感兴趣的:(c++)