关于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++内存管理内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 老生常谈C/C++内存管理

    内存分配方式 简介 在C++中,内存分成5个区,他们分别是堆.栈.自由存储区.全局/静态存储区和常量存储区. 栈:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放.栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限. 堆:就是那些由 new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个 delete.如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收. 自由存储区:就是那些由mall

  • C++如何用智能指针管理内存资源

    1.简介 C++作为一门应用广泛的高级编程语言,却没有像Java.C#等语言拥有垃圾回收(Garbage Collection )机制来自动进行内存管理,这也是C++一直被诟病的一点.C++在发展的过程中,一直致力于解决内存泄漏,C++虽然基于效率的考虑,没有采用垃圾回收机制,但从C++98开始,推出了智能指针(Smart Pointer)来管理内存资源,以弥补C++在内存管理上的技术空白. 智能指针是C++程序员们一件管理内存的利器,使用智能指针管理内存资源,实际上就是将申请的内存资源交由智能

  • C/C++中的内存管理小结

    前言 我们最初熟知的内存开辟方式: int val = 20: 在栈空间上开辟4个字节 char array[10]: 在栈空间上开辟10个字节的连续空间 上述开辟空间的方式有两个特点: 空间开辟大小是固定的. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配. 但是对于空间的需求,不仅仅是上述的情况,有时候我们需要的空大小在程序运行时才能知道,那此时静态的开辟空间的方式就不能满足了,我们这时候只能试试动态内存开辟. 这篇博客就来带大家梳理一下C/C++中的内存管理. 一:C/C

  • 深入理解C++中的new/delete和malloc/free动态内存管理及区别介绍

    malloc/free和new/delete的区别 malloc/free是C/C++标准库的函数:new/delete是C++操作符. malloc/free只是动态分配内存空间/释放空间:new/delete除了分配空间还会调用构造函数和析构函数进行初始化与清理资源. malloc/free需要手动计算类型大小且返回值类型为void*:new/delete可自动计算类型的大小,返回对应类型的指针. malloc/free管理内存失败会返回0:new/delete等的方式管理内存失败会抛出异常

  • 一文秒懂C语言/C++内存管理(推荐)

    C 语言内存管理指对系统内存的分配.创建.使用这一系列操作.在内存管理中,由于是操作系统内存,使用不当会造成毕竟麻烦的结果.本文将从系统内存的分配.创建出发,并且使用例子来举例说明内存管理不当会出现的情况及解决办法. 一.内存 在计算机中,每个应用程序之间的内存是相互独立的,通常情况下应用程序 A 并不能访问应用程序 B,当然一些特殊技巧可以访问,但此文并不详细进行说明.例如在计算机中,一个视频播放程序与一个浏览器程序,它们的内存并不能访问,每个程序所拥有的内存是分区进行管理的. 在计算机系统中

  • 养成良好的C++编程习惯之内存管理的应用详解

    开篇导读    虽然本系列文章定位为科普读物,但本座相信它们不但适合新手们学习借鉴,同时也能引发老鸟们的反思与共鸣.欢迎大家提出宝贵的意见和反馈 ^_^ 在开篇讲述本章主要内容之前,本座首先用小小篇幅论述一下一种良好的工作习惯 -- 积累.提炼与求精.在工作和学习的过程中,不断把学到的知识通过有效的方式积累起来,形成自己的知识库,随着知识量的扩大,就会得到从量变到质变的提升.另外还要不断地对知识进行提炼,随着自己知识面的扩大以及水平的提升,你肯定会发现原有知识库存在着一些片面.局限.笨拙甚至错误

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

    1.内存分配方式 在C++中,内存分成五个区,分别是堆.栈.自由存储区.静态存储区和常量存储区. 1) 栈 执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放.栈内存分配运算内置处理器指令集中,效率很高,但分配的内存容量有限. 2) 堆 由new分配的内存块,释放由程序员控制.如果程序员没有释放,那么就在程序结束的时候,被操作系统回收. 3) 自由存储区 由malloc等分配的内存块,用free结束自己的生命. 4) 静态存储区 全局变量和静态变量被分配到

  • SQLServer的内存管理架构详解

    目录 一.Windows的虚拟内存管理器 二.SQL Server 内存体系结构 2.1.传统(虚拟)内存 2.2.地址窗口扩展 (AWE) 内存 三.从 SQL Server 2012 (11.x) 开始发生的改变 3.1.对内存管理的更改 3.2.对memory_to_reserve所做的更改 四.动态内存管理 4.1.堆栈大小 五.缓冲区管理 5.1.缓冲区管理的工作原理 5.2.支持的功能 5.3.磁盘 I/O 5.4.长 I/O 请求 5.5.长时间 I/O 请求的原因 六.了解非一致

  • MySQL数据操作管理示例详解

    目录 一.查看表和查看表的定义 二.删除表 三.创建表 四.表类型 五.修改表 六.完整性 1.数据完整性 2.使用约束实现数据完整性 3.在数据表上添加约束 4.删除约束 七.添加数据 八.修改数据 九.删除数据 十.SQL语句中的运算符 算数运算符 比较运算符 逻辑运算符 一.查看表和查看表的定义 SHOW TABLE 表名 DESC 表名; DESCRIBE 表名 二.删除表 DROP TABLE [IF EXISTS ] 表名; 如果表USER存在,删除表USER DROP TABLE

  • C语言中动态内存管理图文详解

    目录 1.动态内存开辟的原因 2.动态内存函数的介绍 2.1malloc和free 2.2calloc 2.3realloc 3.常见的动态内存错误 3.1对NULL指针的解引用操作 3.2对动态开辟空间的越界访问 3.3对非动态开辟内存使用free 3.4使用释放一块动态开辟内存的一部分 3.5对同一块动态内存多次释放 3.6动态开辟内存忘记释放(内存泄漏) 4.练习 4.1练习1 4.1练习2 4.3练习3 4.4练习4 5.C/C++程序的内存开辟 总结 1.动态内存开辟的原因 常见的内存

  • C/C++指针与内存管理图文详解

    目录 一.指针 二.数组 总结 指针和内存管理始终是C/C++比较容易模糊的知识点,但在C/C++编程中又绕不开的地方,特别在下位机上,会频繁的与指针打交道,如果概念模糊,一不小心就会写出冗余的代码,可能会引起多余内存开销或者直接影响运行速度. 一.指针 1.计算机内存主要分成这几个区,每个区又分成无数个字节(Byte),每个字节(Byte)都有唯一的编号,而这个编号就这个字节的指针地址.一般程序能读写的区域只有全局变量.堆区.栈区.下面是计算机内存的示意图: 每个字节(Byte)对应的编号地址

  • c++对象内存布局示例详解

    目录 前言 继承对象的内存布局 具有多重继承和虚拟功能的对象的内存布局 总结 前言 了解你所使用的编程语言究竟是如何实现的,对于C++程序员可能特别有意义.首先,它可以去除我们对于所使用语言的神秘感,使我们不至于对于编译器干的活感到完全不可思议:尤其重要的是,它使我们在Debug和使用语言高级特性的时候,有更多的把握.当需要提高代码效率的时候,这些知识也能够很好地帮助我们. 简单非多态的内存布局 class X { int x; float xx; public: X() {} ~X() {}

  • vue中Axios的封装和API接口的管理示例详解

    目录 一.axios的封装 安装 引入 环境的切换 设置请求超时 post请求头的设置 请求拦截 响应的拦截 封装get方法和post方法 axios的封装基本就完成了,下面再简单说下api的统一管理. 2018.8.14更新 我们所要的说的axios的封装和api接口的统一管理,其实主要目的就是在帮助我们简化代码和利于后期的更新维护. 一.axios的封装 在vue项目中,和后台交互获取数据这块,我们通常使用的是axios库,它是基于promise的http库,可运行在浏览器端和node.js

  • 关于C++对象继承中的内存布局示例详解

    前言 本文给大家介绍的是关于C++对象继承的内存布局的相关内容,分享出来供大家参考学习,在开始之前说明下,关于单继承和多继承的简单概念可参考此文章 以下编译环境均为:WIN32+VS2015 虚函数表 对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的.简称为V-Table.在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承.覆盖的问题,保证其容真实反应实际的函数. 首先先通过一个例子来引入虚函数表,假如现在有三

  • JavaScript中的垃圾回收与内存泄漏示例详解

    前言 程序的运行需要内存.只要程序提出要求,操作系统或者运行时就必须供给内存.所谓的内存泄漏简单来说是不再用到的内存,没有及时释放.为了更好避免内存泄漏,我们先介绍Javascript垃圾回收机制. 在C与C++等语言中,开发人员可以直接控制内存的申请和回收.但是在Java.C#.JavaScript语言中,变量的内存空间的申请和释放都由程序自己处理,开发人员不需要关心.也就是说Javascript具有自动垃圾回收机制(Garbage Collecation). 一.垃圾回收的必要性 下面这段话

  • C语言动态内存管理malloc柔性数组示例详解

    目录 1.1为什么存在动态内存管理 1.2动态内存管理函数 1.2.1malloc 1.2.2free 1.2.3calloc 1.2.4realloc 1.3动态内存管理函数易错点 1.3.1对NULL指针的解引用操作 1.3.2对动态开辟空间的越界访问 1.3.3对非动态开辟内存使用free释放 1.3.4使用free释放一块动态开辟内存的一部分 1.3.5对同一块动态内存多次释放 1.3.6动态开辟内存忘记释放(内存泄漏) 2.1常见相关笔试题 2.2C/C++语言中的内存开辟 2.3柔性

随机推荐