关于C/C++内存管理示例详解

 更新时间:2021年05月08日 10:01:59   作者:程序员欢欢  
这篇文章主要给大家介绍了C/C++内存管理的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1、内存分配方式

在C++中,内存分成五个区,分别是堆、栈、自由存储区、静态存储区和常量存储区。

1) 栈

执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置处理器指令集中,效率很高,但分配的内存容量有限。

2) 堆

由new分配的内存块,释放由程序员控制。如果程序员没有释放,那么就在程序结束的时候,被操作系统回收。

3) 自由存储区

由malloc等分配的内存块,用free结束自己的生命。

4) 静态存储区

全局变量和静态变量被分配到同一块内存中。C语言中,全局变量分为已初始化和未初始化。

5) 常量存储区

里面存放的是常量,不允许修改。 

2、堆和栈的区别

int * ptr = (int*)malloc(sizeof(int)*4);

在栈中存放了一个指向堆内存的指针ptr。在程序会先确定在堆中分配内存的大小,然后利用operator new分配内存,然后放回这块内存的首地址,放在栈中。

1) 空间大小不同

在32位系统中,堆的空间是4G,而栈的空间很小。

2) 分配方式不同

堆是动态分配的,没有静态分配。栈的静态分配时编译器完成的,动态分配由alloca函数分配。栈的动态分配由编译器进行释放。

3) 管理方式不同

栈是由编译器自动管理。堆的释放是由程序员控制。

4) 生长方式不同

堆的生长方式是向上的,向着内存地址增加的方向。栈的生长方式是向下的,是向着内存地址减小的方向。

5) 能否产生碎片

对于堆,频繁的new/delete会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。

6) 分配效率不同

栈是机器系统系统的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定栈的效率比较高。

堆是C/C++函数库提供的,库函数会按照一定的算法,在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。

3、operator new和operator delete

3.1 为什么要进行重载?

在嵌入式系统中,由于内存的限制,频繁的动态分配不定大小的内存会引起很大的问题以及堆破碎的风险。

当你必须要使用new和delete的时候,你不得不控制C++中的内存分配。你需要用重载的全局new和delete代替系统的内存分配符。需要给类重载new和delete。

一个防止内存破碎的方法是从不同固定大小的内存池中分配不同类型的对象。对单个类重载new和delete,你就可以灵活的控制内存分配。

3.2 重载全局的new和delete操作符

void* operator new(size_t size)
{
	void* p = malloc(size);
	return (p);
}

void operator delete(void*p)
{
	free(p);
}

3.3 类重载new和delete

为单个类重载new和delete

class TestClass
{
public:
	void* operator new(size_t size)
	{
		void* p = malloc(size);
		return p;
	}
	void operator delete(void* p)
	{
		free(p);
	}
};

为单个类重载new[] 和 delete[]

class TestClass
{
public:
	void* operator new[](size_t size)
	{
		void* p = malloc(size);
		return p;
	}
	void* operator delete[](void* p)
	{
		free(p);
	}
}

int main()
{
	TestClass* p  = new TestClass[10];
	delete [] p; 
	return 0;
}

注意:new[] 中的个数参数是数组的大小加上额外的存储对象数目的字节。考虑到内存分配机制的因素,尽量避免使用对象数组。

4、有了malloc/free为什么还要new/delete

malloc和free是C/C++语言的标准库函数,new / delete是C++ 的运算符。都用于申请动态内存和释放内存。

malloc / free 无法满足动态对象的要求。对象在创建的同时同时自动执行构造函数,对象消亡之前自动执行析构函数。即就是C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理和释放内存工作的运算符delete。

内部数据类型的对象没有析构和构造的过程,所以对于他们来说malloc / free和new / delete是等价的。

5、内存耗尽的三种解决方法

在申请动态内存时,找不到足够大的内存块,malloc和new将返回NULL指针。

1)判断指针是否为NULL,如果是则使用 return 终止函数

2)判断指针是否为NULL,如果是则使用 exit(1) 终止程序

3)为malloc和new 设置异常处理函数 。

总结

到此这篇关于C/C++内存管理的文章就介绍到这了,更多相关C/C++内存管理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 利用C语言实现将格式化数据和字符串相互转换

    利用C语言实现将格式化数据和字符串相互转换

    这篇文章主要为大家详细介绍了2个函数,分别是sprintf和sscanf,可以用来实现将格式化数据和字符串相互转换,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-03-03
  • C语言实现宿舍管理系统课程设计

    C语言实现宿舍管理系统课程设计

    这篇文章主要为大家详细介绍了C语言实现宿舍管理系统课程设计,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • C语言之复杂链表的复制详解

    C语言之复杂链表的复制详解

    这篇文章主要为大家详细介绍了C语言之复杂链表的复制,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-07-07
  • C++中引用的使用总结

    C++中引用的使用总结

    以下是对C++中引用的使用进行了详细的总结介绍,需要的朋友可以过来参考下,希望对大家有所帮助
    2013-10-10
  • C++/JAVA/C#子类调用父类函数情况总结

    C++/JAVA/C#子类调用父类函数情况总结

    今天小编就为大家分享一篇关于C++/JAVA/C#子类调用父类函数情况总结,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • VS2019调试C语言程序(监视操作)的详细步骤

    VS2019调试C语言程序(监视操作)的详细步骤

    在很多时候我们在写程序的过程中会发现一些非编程错误的问题,这样的问题很难直接分辨出来,但是我们可以用调试了一步一步的模拟程序运行的过程,来找出程序的错误,下面这篇文章主要给大家介绍了关于VS2019调试C语言程序(监视操作)的详细步骤,需要的朋友可以参考下
    2022-11-11
  • Windows下Qt读取系统的内存、CPU、GPU等使用信息的示例代码

    Windows下Qt读取系统的内存、CPU、GPU等使用信息的示例代码

    在当今计算机应用广泛的领域中,了解系统的内存、CPU和GPU使用情况是非常重要的,本文将介绍如何使用Qt和Windows API来读取系统的内存、CPU和GPU使用详细信息,将提供一个完整的示例代码,需要的朋友可以参考下
    2024-01-01
  • C/C++预处理浅析使用形式

    C/C++预处理浅析使用形式

    预处理是指在进行编译的词法扫描和语法分析之前所作的工作。预处理指令指示在程序正式编译前就由编译器进行的操作,可放在程序中任何位置。处理完毕自动进入对源程序的编译。C/C++中的预处理主要包含三种:文件包含、宏定义、条件编译
    2022-09-09
  • OpenCV中C++函数imread读取图片的问题及解决方法

    OpenCV中C++函数imread读取图片的问题及解决方法

    利用C++函数imread读取图片的时候返回的结果总是空,而利用C函数cvLoadImage时却能读取到图像。怎么回事?今天小编通过本教程给大家简单说明原因
    2017-03-03
  • C语言的字符函数和字符串函数详解

    C语言的字符函数和字符串函数详解

    这篇文章主要为大家介绍了C语言的字符函数和字符串函数,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01

最新评论