IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> c++图解内存管理 -> 正文阅读

[C++知识库]c++图解内存管理

c&c++内存管理

1.了解一些基本的内存段(图演示)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cvc8Pg5v-1662721223978)(C:\Users\Cherish\AppData\Roaming\Typora\typora-user-images\image-20220909150153993.png)]


验证栈是向下生长的

#include<iostream>
using namespace std;

int main()
{
	int a = 3;
	int b = 4;
	int c = 5;
	int d = 6;
	cout <<"a:"<< &a << endl;
	cout << "b:"<<&b << endl;
	cout << "c:"<<&c << endl;
	cout << "d:"<<&d << endl;
	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p0uAzdZ7-1662721223980)(C:\Users\Cherish\AppData\Roaming\Typora\typora-user-images\image-20220909150331712.png)]


验证堆一般是向上生长的(不一定)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZbXWkaAG-1662721223982)(C:\Users\Cherish\AppData\Roaming\Typora\typora-user-images\image-20220909150458987.png)]


#include<iostream>
using namespace std;

int main()
{
	int num = 10;

	while (num--)
	{
		int *p1 = (int*)malloc(sizeof(int));
		int *p2 = (int*)malloc(sizeof(int));

		cout <<"p1"<< p1 << endl;
		cout <<"p2"<<p2 << endl;
		cout << endl;

		free(p1);
	}
	return 0;
}

一般情况下,p1的地址是比p2的地址高的(因为堆一般是向上生长的),但是有时候是不一定的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YA6XBQTd-1662721223984)(C:\Users\Cherish\AppData\Roaming\Typora\typora-user-images\image-20220909150957425.png)]


习题检测,巩固内存管理知识点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QSOGc1gW-1662721223987)(C:\Users\Cherish\AppData\Roaming\Typora\typora-user-images\image-20220909151143358.png)]


答案

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JX4YNH5N-1662721223989)(C:\Users\Cherish\AppData\Roaming\Typora\typora-user-images\image-20220909151326885.png)]


温馨提示:题目中的指针是局部指针变量,是在栈上的,但是它指向的内容(解引用)可能是堆区或者常量区的。,可以画画图理解理解


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0ORAJtYl-1662721223990)(C:\Users\Cherish\AppData\Roaming\Typora\typora-user-images\image-20220909152715315.png)]


2.c++申请动态内存的新玩儿法new,delete

回顾c语言动态内存管理的方式

malloccallocrealloc

  1. malloc堆上动态开空间

  2. calloc堆上动态开空间+初始化成0等价于malloc+memset

  3. realloc指针已有的空间扩容

    原题增容–后面又足够的空间

    异地增容–后面没有足够的空间

开辟内置类型的空间

//C++开辟动态内存的新玩法
//语法演示:
#include<iostream>
using namespace std;

int main()
{
	//申请一个int的动态空间
	int* p1 = (int*)malloc(sizeof(int));
	*p1 = 1;
	int* p2 = new int(2);//这里是初始化

	free(p1);
	delete p2;

	//申请一个10各int的动态数组
	int *p3 = (int*)malloc(sizeof(int)* 10);
	for (int i = 0; i < 10; i++)
	{
		p3[i] = i + 1;
	}
	int *p4 = new int[10]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};//初始化

	free(p3);
	delete[]p4;
	return 0;
}

跟c语言的版本相比,c++的版本,初始化时显得比较方便,而且语法比较简洁。当然了,更大的优越性还在后面。


开辟自定义类型的空间(请用vs2013以上版本测试代码)

#include<iostream>
using namespace std;

struct ListNode
{

	int _val;
	ListNode* _next;
	ListNode* _prev;

	//构造函数
	ListNode(int val = 0)
	:_val(val)
	, _next(nullptr)
	, _prev(nullptr)
	{
        cout<<"ListNode(int val = 0)"<<endl;
    }
	
	~ListNode()
	{
		cout << "ListNode()" << endl;
	}
};

int main()
{
	//申请一个结点的空间
    ListNode* pa = (ListNode*)malloc(sizeof(ListNode)*4);
	ListNode* pb = new ListNode(1);//不用去用sizeof去计算空间大小,很方便   
	free(pa);
	delete pb;

	//申请4个结点的空间--当然了一般不会这么玩儿,我们只是看看效果
	ListNode* pc = (ListNode*)malloc(sizeof(ListNode)* 4);
	ListNode* pd = new ListNode[4]{1, 2, 3, 4};

	free(pc);
	delete[]pd;

	return 0;
}

? 学过c语言版本的数据结构的小伙伴都知道,我们push_back一个结点时,需要先实现一个buynewnode的函数(创建一个结点,并且对其进行初始化)。而new这个操作符,在创建结点的同时,已经帮我们实现了结点的初始化。调用了构造函数,而且delete还调用了析构函数。

总结一下

  1. c++中,如果是申请内置类型对象或者数组,mallocnew没有太大区别
  2. 如果时自定义类型,区别很大,new和delete时开空间+初始化析构清理+释放空间mallocfree仅仅时开空间+释放空间
  3. 建议在c++中,无论时内置类型还是自定义类型的申请释放,尽量使用new和delete

3. 32位平台下可以开辟多大的内存

我:cpu过来遭罪
cpu:你不要过来啊
在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iDGYP8oA-1662721223992)(C:\Users\Cherish\AppData\Roaming\Typora\typora-user-images\image-20220909155816881.png)]

上述程序,我们开了1.8 G左右的内存,加上需要堆上的小内存,最后的综合有2 G的空间


如何开辟4 G的内存

将项目属性修改一下,改成64位平台即可,64位平台有2^34 G的空间(虚拟内存)在这我们不做细说,因为我也不太了解Linux。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LJbYU4Lc-1662721223993)(C:\Users\Cherish\AppData\Roaming\Typora\typora-user-images\image-20220909160504612.png)]


4.了解operator newoperator delete

new其实是operator new + 构造函数

delete其实是operator delete+构造函数

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

大家可以将operator new和operator delete理解成和malloc 和free一样用法的函数。

唯一不同的地方是,operator new和malloc开辟空间失败的处理方式不一样,malloc是返回NULL空指针,而operator是抛异常,下面代码让大家看看效果,不必深究,以后会有介绍。

struct ListNode
{

	int _val;
	ListNode* _next;
	ListNode* _prev;

	//构造函数
	ListNode(int val = 0)
		:_val(val)
		, _next(nullptr)
		, _prev(nullptr)
	{
		cout << "ListNode(int val = 0)" << endl;
	}

	~ListNode()
	{
		cout << "ListNode()" << endl;
	}
};

void f()
{
	// 他的用法跟malloc和free是完全一样的,功能都是在堆上申请释放空间
	// 失败了处理方式不一样,malloc失败返回NULL,operator new失败以后抛异常
	ListNode* p1 = (ListNode*)malloc(sizeof(ListNode));
	free(p1);

	ListNode* p2 = (ListNode*)operator new(sizeof(ListNode));
	operator delete(p2);


	void* p3 = malloc(0x7fffffff);
	if (p3 == NULL)
	{
		cout << "malloc fail" << endl;
	}

	void* p4 = operator new(0x7fffffff);

	ListNode* p5 = new ListNode(2);

	cout << "继续" << endl;
}
//
//
int main()
{
	try
	{
		f();
	}
	catch (exception& e)
	{
		cout << e.what() << endl;
	}

	return 0;
}

malloc失败返回NULL,程序还会继续向下执行,但是operator new失败,就会报异常,f函数后面的没有在继续执行,然后走进catch语句中。


5.operator newoperator delete的类函数重载–了解即可

struct ListNode//目的是提高效率
{
	ListNode* _next;
	ListNode* _prev;
	int _val;

	// 类中重载专属operator new
	void* operator new(size_t n)
	{
	void* p = nullptr;
	p = allocator<ListNode>().allocate(1);
	cout << "memory pool allocate" << endl;
	return p;
	}

	void operator delete(void* p)
	{
		allocator<ListNode>().deallocate((ListNode*)p, 1);
		cout << "memory pool deallocate" << endl;

	}

	ListNode(int val)
		:_next(nullptr)
		, _prev(nullptr)
		, _val(val)
	{}
};

int main()
{
	ListNode* p = new ListNode(1);
	delete p;
	
	return 0;
}

如果你自己在类里面写了operator newoperator delete,那么编译器就不会去调用系统提供的了,这是一种提高效率的方式。

我们是可以通过反汇编来看效果的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bvkeff44-1662721223995)(C:\Users\Cherish\AppData\Roaming\Typora\typora-user-images\image-20220909162547713.png)]


6.定位new–placement-new

通过上述的学习我们知道,malloc,和operator是不会去调用构造函数的,new会去调用构造函数,而且构造函数是只允许构造出对象时调用,而你的对象创建出来之后是无法调用构造的。

但是如果我们operator new了一块空间(未初始化),但是又想要调用其构造函数,该怎们办呢?

class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A(int a = 0)" << endl;
	}

	~A()
	{

		cout << "~A()" << endl;
	}

private:
	int _a;
};

int main()
{
	A* pa = (A*)operator new(sizeof(A));
	//pa->A();//error错误调用方式,构造函数只允许构造时进行调用
	new(pa)A; // 定位new,placement-new,显示调用构造函数初始化这块对象空间

	A* pb = (A*)operator new(sizeof(A));
	new(pb)A(3);
    
    A* pc = new A;
	new(pc)A(3);

	// 等于 delete p
	pa->~A(); // 析构函数可以显示调用
	operator delete(pa);

	pb->~A();
	operator delete(pb);
    
    delete pc;
	return 0;
}

大家要知道定位new哦,他是一种对已经创建出来的对象,还能继续调用其构造函数的方式。


7.malloc/freenew/delete的区别–常考面试题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xeNelsEo-1662721223997)(C:\Users\Cherish\AppData\Roaming\Typora\typora-user-images\image-20220909163514648.png)]


8.再次理解内存泄漏

首先大家先想一想这个问题:内存泄漏是指针丢了是内存丢了

内存管理中,内存是用指针去维护的,当你的动态内存空间还没有释放时,你已经把指针弄丢了,那么你将无法控制这段空间,进而导致内存泄漏。

什么是内存泄漏,内存泄漏的危害

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

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


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gxBTy38v-1662721223998)(D:\gitee仓库\博客使用的表情包\给点赞吧.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s5l3clT4-1662721223999)(D:\gitee仓库\博客使用的表情包\要赞.jpg)]

感谢大家的观看!

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-13 10:54:41  更:2022-09-13 10:55:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/29 3:53:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码