iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++ 内存管理原理分析
  • 919
分享到

C++ 内存管理原理分析

2024-04-02 19:04:59 919人浏览 八月长安
摘要

目录1.C/C++中程序内存分布1.1 内存分布图1.2 小试牛刀2.C语言部分的动态内存管理方式3.c++内存管理方式3.1new/delete操作内置类型3.2 new

1.C/C++中程序内存分布

C/C++中程序内存区域大致划分为:内核空间(这部分用户不能读写)、栈、内存映射段、堆、数据段(存储全局数据、静态数据)、代码段(存储可执行代码、只读常量,又称常量区)。

1.1 内存分布图

image-20211118094900676

1.2 小试牛刀

接下来看下如下代码,思考下每一个变量分别在哪个内存区域?


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";
	char *pchar3 = "abcd";//有的编译器会报错,需要用const char 
	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(ptr2);
}

上述代码段对应变量区域划分如下:

image-20211118095816959

2.C语言部分的动态内存管理方式

再来回顾一下之前C语言部分的动态内存管理方式:malloc / calloc/ realloc和free

带着两个问题阅读下述程序段:

1.malloc / calloc/ realloc的区别是什么?

2.最后需要free(p2)吗?


void Test()
{
	int* p1 = (int*)malloc(sizeof(int));
	free(p1);

	int* p2 = (int*)calloc(4, sizeof(int));
	int* p3 = (int*)realloc(p2, sizeof(int) * 10);

	free(p3);
}

答:

1.calloc相当于malloc+memset(0),即开空间+初始化。

2.realloc是对malloc/calloc的空间进行扩容,扩容之下又涉及到了咱们前面所讲的原地扩容和异地扩容俩种情景:原地扩容p2和p3是一样的,也有可能是异地扩容,那么p2指向的空间已经被释放了,所以两种情况下我们都可以不需要处理p2。

image-20211118101324827

3.C++内存管理方式

总之就是C语言那套内存管理方式相对麻烦,所以C++提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理.

3.1new/delete操作内置类型

1.开辟单个元素

开辟单个元素基本语法: type * ptr = new type(content); ,可以理解成动态申请一个type类型的空间并将其中内容初始化为content,当然,你也可以选择不初始化。

释放空间语法: delete name;

例:


int* a = new int(100);  //动态申请一个int类型的空间并初始化为100
delete a;

2.开辟n个type类型的空间

开辟n个type类型基本语法: type* name = new type[n]

删除的基本语法:delete[] name;

例:


int* ptr = new int[100];//动态申请100个int类型的空间
delete[] ptr;           //注意哦!一定要匹配哦!不然必崩溃!

3.对于内置类型,malloc/free和new/delete确实没有什么区别,二者的作用完全一样。

例:


int main()
{
	//malloc向内存申请4个整型大小的空间
	int* p1 = (int*)malloc(sizeof(int) * 4);
	//new向内存申请4个整型大小的空间
	int* p2 = new int[4];
	//free释放掉p1申请的空间
	free(p1);
	p1 = nullptr;
	//delete释放掉p2申请的空间
	delete[] p2;
	return 0;
}

image-20211118103800232

3.2 new/delete操作自定义类型


class  Date
{
public:
	Date(int year=2021, int month=1, int day=1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};


int main()
{
	//malloc申请十个Date空间
	Date* p1 = (Date*)malloc(sizeof(Date) * 10);
	free(p1);

	//new申请十个Date空间
	Date* p2 = new Date[10];
	delete[] p2;

	return 0;
}

区别:在申请自定义类型空间的时候,new会调用构造函数,delete会调用析构函数,而mallo和free不会哦!

4.new和delete底层实现原理(important!!!)

image-20211118121205737

在讲解他们的底层实现原理之前需要先先介绍一下两个全局函数,分别是operator newoperator delete.

new和delete是用户进行动态内存申请和释放的操作符,operator new和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过调用operator delete全局函数来释放空间。

4.1operator new/operator delete

operator new封装了 malloc 和失败抛异常俩个部分,

下面是operator new的代码:


void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
	// try to allocate size bytes
	void* p;
	while ((p = malloc(size)) == 0)              //如果开辟成功就不会进入循环,并且可以清晰
		if (_callnewh(size) == 0)
		{
			// report no memory
			// 如果申请内存失败了,这里会抛出bad_alloc 类型异常
			static const std::bad_alloc nomem;
			_RAISE(nomem);
		}
	return (p);
}

类似的,operator delete封装了free

下面是operator delete的代码:


void operator delete(void* pUserData)
{
	_CrtMemBlockHeader* pHead;
	RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
	if (pUserData == NULL)
		return;
	_mlock(_HEAP_LOCK); 
	__TRY
		
		pHead = pHdr(pUserData);
	
	_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
	_free_dbg(pUserData, pHead->nBlockUse);
	__FINALLY
		_munlock(_HEAP_LOCK); 
	__END_TRY_FINALLY
		return;
}

总结:通过观察上述俩个全局函数的实现,不难发现operator new实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常,operator delete最终是通过free来释放空间的。

4.2new和delete的实现原理

内置类型

malloc/free与new/delete在处理内置类型时并没有区别,只是malloc申请空间失败时返回空指针,而new申请空间时是抛异常,new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间。

自定义类型

1.new的原理:1.调用operator new函数申请空间。2.在申请空间上执行构造函数,完成对象的初始化。

2.delete的原理:1.在空间上执行析构函数,完成对象中资源的清理工作。2.调用operator delete函数释放空间。

另外new T[N]的原理:调用operator new[]函数,在operator new[]中实际调用N次operator new函数完成N个对象空间的申请,然后在申请的空间上执行N次构造函数。**delete[]的原理:**在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理。然后调用operator delete[]释放空间,实际在operator delete[]中调用N次operator delete来释放空间。

初学者看到“delete调用析构函数,完成对象资源的清理工作,后边又调用operator delete函数释放空间”这部分内容时可能会比较混乱,这里以栈为例子详细说下:


struct Stack
{
	int* _a;
	int _top;
	int _capacity;
	Stack(int capacity = 4)
		:_a(new int[capacity])
		,_size(0)
		,_capacity(capacity)
	{
		cout << "Stack(int capacity = 4)" << endl;
	}
	~Stack()
	{
		delete _a;
		_top = _capacity = 0;
		cout << "~Stack()" << endl;
	}
};

int main()
{
	Stack st;

	Stack* ps = new Stack;
	delete ps;
	return 0;
}

image-20211118143509751

首先,创建st变量,存放在栈当中,然后调用构造函数_a申请空间(对应上图动作1)。

接着,对于ps,会先去堆上调用operator new开辟一块空间(对应上图动作2),再调用构造函数对对象进行初始化,初始化时_a又会申请空间(对应上图动作3)

最后,delete[] ps,会先调用析构函数完成对象资源的清理,即释放_ a申请的空间,然后调用operator delete释放ps申请的空间,然后调用析构函数 _ a申请的空间。(就是步骤321)

5.相关面经

5.1malloc/free与new/delete的区别

1.malloc/free是函数,而new/delete是操作符。

2.malloc申请的空间不会初始化,而new申请的空间可以初始化(内置类型new也不会初始化)。

3.malloc申请空间时需要手动计算要申请的空间的字节数,而new申请空间只需要所申请的类型即可。

4.malloc的返回值为void*,使用是需要强制类型转换,而new不需要,因为new跟的是空间的类型。

5.对于申请内存失败,malloc的处理是返回空指针NULL,而new的处理是抛异常

6.对于自定义类型,new/delete会调用其构造/析构函数,而malloc/delete不会。

5.2什么是内存泄漏?

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

image-20211118150110386

5.3内存泄漏的危害

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

比如王者荣耀后台服务,长期运行,只有升级的时候才会停,内存泄漏会导致可用内存越来越少,程序越来越慢,甚至挂掉。

再比如物联网设备:各种智能家居、智能机器人等等,它们内存很小,也经不起内存泄漏的折腾。

by the way,对于C++我们需要主动释放内存,但是在Java当中,不再需要主动释放内存,Java后台有垃圾回收器,接管了内存释放(所以Java写得好舒服,呜呜呜)

5.4如何预防内存泄漏(先了解一下,后续作者再详细介绍)

1.智能指针

2.内存泄漏检测工具

2.1在linux环境下:

image-20211114145524213

2.2在windows环境下使用第三方工具:VLD工具

img

原理:以Visual Leak Detector为例,其工作分为3步,首先在初始化注册一个钩子函数;然后在内存分配时该钩子函数被调用以记录下当时的现场;最后检查堆内存分配链表以确定是否存在内存泄漏并将泄漏内存的现场转换成可读的形式输出。

感谢您的阅读!!!如果内容对你有帮助的话,记得给我三连(点赞、收藏、关注)——做个手有余香的人。

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

--结束END--

本文标题: C++ 内存管理原理分析

本文链接: https://www.lsjlt.com/news/157833.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++ 内存管理原理分析
    目录1.C/C++中程序内存分布1.1 内存分布图1.2 小试牛刀2.C语言部分的动态内存管理方式3.C++内存管理方式3.1new/delete操作内置类型3.2 new...
    99+
    2024-04-02
  • C#内存管理举例分析
    本篇内容主要讲解“C#内存管理举例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#内存管理举例分析”吧!C#内存管理C#内存管理提供了与java一样的自动内存管理功能,让程序员从繁重的内存...
    99+
    2023-06-17
  • C/C++内存管理的示例分析
    这篇文章主要介绍了C/C++内存管理的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。C/C++赋予程序员管理内存的自由,是C/C++语言特色,虽然这引入了复杂度和危险...
    99+
    2023-06-15
  • java内存管理关系及内存泄露的原理分析
    目录java内存管理关系及内存泄露原理java对象和内存的关系创建对象null的作用内存泄露检测内存泄露的原理java内存管理关系及内存泄露原理 这可能是最近写的博客中最接近底层的了...
    99+
    2024-04-02
  • C++内存管理原理是什么
    这篇文章主要讲解了“C++内存管理原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++内存管理原理是什么”吧!1.C/C++中程序内存分布C/C++中程序内存区域大致划分为:内核空...
    99+
    2023-06-25
  • C++中内存管理的示例分析
    这篇文章将为大家详细讲解有关C++中内存管理的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。概述内存管理的原理庞大而复杂,然而这些都被操作系统进行了封装,并对外预留了API,这些api被c++调用...
    99+
    2023-06-25
  • C语言与C++内存管理超详细分析
    目录一、内存1.1 内存四区1.2 使用代码证实内存四区的底层结构二、malloc 和 free2.1 malloc 和 free 的使用2.2 内存泄漏与安全使用实例与讲解三、ne...
    99+
    2024-04-02
  • C++内存管理详细解析
    目录一、C++内存管理1、 new/delete表达式2、new/delete重载3、类内自定义allocator(per-class allocator) 二、多线程内存分配器1、...
    99+
    2024-04-02
  • C++图文并茂分析讲解内存管理
    目录1.了解一些基本的内存段(图演示)验证栈是向下生长的验证堆一般是向上生长的(不一定)巩固内存管理知识点答案2.c++申请动态内存的新玩儿法new,delete回顾c语言动态内存管...
    99+
    2024-04-02
  • C#指针内存控制Marshal内存数据存储原理分析
    目录了解内存的原理了解指针的原理1、通过指针修改 值类型 的变量数据2、通过指针修改 引用类型 的变量数据3、通过指针修改 数组对象 的成员数据4、通过指针修改 类对象 的字段数据5...
    99+
    2023-02-26
    C#指针 指针Marshal C#内存数据存储原理
  • C语言动态内存管理分析总结
    目录什么是动态内存分配动态内存函数的介绍freemalloccallocrealloc动态内存管理中常见的错误对NULL指针的解引用操作对动态开辟空间的越界访问对非动态开辟内存使用f...
    99+
    2024-04-02
  • Python内存管理的原理
    这篇文章主要介绍“Python内存管理的原理”,在日常操作中,相信很多人在Python内存管理的原理问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Python内存管理的原理”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-15
  • 【C++】C&C++内存管理
    就是你被爱情困住了?Wake up bro! 文章目录 一、C/C++内存分布二、C语言中动态内存管理方式三、C++中内存管理方式1.new和delete操作内置类型2.new和delete...
    99+
    2023-09-03
    c++ c语言 java 开发语言
  • C/C++中指针与内存管理的示例分析
    这篇文章主要介绍了C/C++中指针与内存管理的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。指针和内存管理始终是C/C++比较容易模糊的知识点,但在C/C++编程中又...
    99+
    2023-06-29
  • 分析JS中的内存管理
    这篇文章主要讲解了“分析JS中的内存管理”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“分析JS中的内存管理”吧!前言像C语言这样的底层语言一般都有底层的内存...
    99+
    2024-04-02
  • C++ 内存管理:自定义内存分配器
    c++++ 中的自定义内存分配器可让开发者根据需求调整内存分配行为,创建自定义分配器需要继承 std::allocator 并重写 allocate() 和 deallocate() 函...
    99+
    2024-05-03
    c++ 内存管理
  • C语言中动态内存管理实例分析
    今天小编给大家分享一下C语言中动态内存管理实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1.动态内存开辟的原因常见的...
    99+
    2023-07-02
  • Java中内存分配的原理分析
    Java中内存分配的原理分析,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。深入Java核心Java内存分配原理精讲Java内存分配与管理是Java的核心技术之一,之前我们曾...
    99+
    2023-06-17
  • C++ 内存管理中的原子操作
    原子操作在多线程环境下管理共享内存至关重要,确保对内存的访问是彼此独立的。c++++ 标准库提供原子类型,如 std::atomic_int,并提供成员函数如 load() 和 stor...
    99+
    2024-05-03
    原子操作 c++ 内存管理 c++ 并发访问 标准库
  • 【C++】C&C++内存管理
    就是你被爱情困住了?Wake up bro! 文章目录 一、C/C++内存分布二、C语言中动态内存管理方式三、C++中内存管理方式1.new和delete操作内置类型2.new和delete操作自定义类型(仅限vs的底层实现机制,...
    99+
    2023-08-21
    c++ c语言 java 开发语言
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作