从C到C++——C++的内存管理

本文深入探讨了内存管理的重要性,解析了C++中的内存区域,包括栈、堆和自由存储区,以及new与malloc的区别。此外,介绍了智能指针作为C++中解决内存管理问题的手段,以及Java的垃圾回收机制,阐述了其自动内存管理的优势和对程序员的影响。通过对C++和Java的对比,突显了各自在内存管理上的特点和适用场景。
摘要由CSDN通过智能技术生成

一、为什么要研究内存管理

1、程序就是数据加算法
(1)写程序是为了解决某个问题,生活中的问题最终被计算机抽象为控制或运算

(2)CPU中的主要构件就是运算器和控制器,本质上是一堆组合逻辑电路,表现为机器指令集

(3)一个问题对应一个程序,一个程序分为多个函数,一个函数分为多个机器指令

(4)存储机器指令需要内存(ROM),机器指令的执行过程需要内存(RAM)参与,这是内存的2大作用

(5)算法对应机器指令(ROM内存),数据对应RAM内存,CPU对应工作机器

(6)越是偏底层的语言,越对内存管理具体化,效率也越高,同时对编程者要求也越高

2、计算机中如何管理内存
(1)C++项目大多数对应在操作系统中运行,很少有裸机的

(2)OS提供最基本的内存管理体系,OS直接管理物理内存,并向应用层提供一套内存接口

(3)C++语言对OS的内存接口进行封装,提供给编程者一套内存使用方法

(4)编程人员写的代码在编译工具链、OS等体系的帮助下最终在计算机物理层运行

3、总结
(1)内存管理的原理虽然庞大而复杂,然而程序员只需要掌握好C++语言的内存管理语言特性即可

(2)C++程序容易出bug,主要就是因为内存管理部分的复杂性

(3)Java,python等语言提供了更多的封装,所以降低了程序员操作难度和犯错可能性

二、C++可用内存区域

1、C语言可用内存区域
(1)栈,对应局部变量

(2)全局数据区/静态数据区,对应全局变量,静态局部变量

(3)const数据区,在内存层面是不存在的,是C编译器营造出来的,通过编译器的检查来实现只读,实际上并没有这样一个数据区

(4)代码段,放可执行程序的,性质是rom,不是内存,但实质是ram

(5)堆heap,由malloc和free来管理的一块内存,也是动态内存

2、C++新增内存区域
自由存储区,由new申请得到的动态内存区域

3、总结
(1)代码段只会读不会写,一般不会出任何问题
(2)全局数据区和栈区都是自动管理的,只要可用内存足够不会出问题
(3)const数据区实际上是由编译器来保证只读的,本质就是普通的内存区域
(4)灵活性和风险都集中在heap区域,常见问题如内存泄漏、内存碎片等

三、new和malloc的区别

1、简单区别
(1)malloc是C库函数,new是C++运算符关键字

(2)malloc申请空间大小靠传参确定,而new不需要传参,对象本身大小由编译器自动计算给出

(3)malloc返回值为void *因此需要强转,而new返回值类型为确定的对象指针类型

(4)malloc对应free释放,new对应delete和delete[]释放

2、深度区别
(1)malloc 只能申请内存不能带初始化,而new可以带初始化

int *p = new int(3);//即*p = 3;
int *p = new int;//即*p = 0;

(2)new会执行类的构造函数而malloc不会

(3)malloc失败返回NULL,而new失败引发bad_alloc异常

(4)申请和释放数组类型时不同
new申请的是数组类型时使用delete[]释放,不是则用delete释放

3、总结
(1)linux平台中new内部是通过malloc实现的,new比malloc多一个调用构造函数

(2)malloc只是返回一块荒地给你,而new会给你修好路盖好房子规划好田地等

四、智能指针的引入

1、指针的优势和劣势
(1)指针的本质是一个变量,变量的值是其他对象的地址,因此可以解引用

(2)指针本质上对应CPU指令中的间接寻址,所以指针是天然存在的,是CPU设计决定了的

(3)指针的优势就是灵活、代码效率高

(4)指针的劣势是太灵活,尤其结合动态内存和构造(比如越界访问)、析构后,在复杂业务中容易出错

2、如何解决
(1)底层不用指针是不可能的,因此这个问题是绕不开的

(2)解决方案1:由程序员来自主把控,C/C++典型编程就是这样

(3)解决方案2:由程序员和专门设计的自动管理机制共同把控,典型代表是智能指针

(4)解决方案3:由自动管理机制全权把控,程序员不用管,典型代表是Java的垃圾回收机制

3、智能指针如何实现
(1)将普通的简单纯指针封装为栈式复合指针对象,即智能指针对象

(2)智能指针本身定义为局部变量,分配在栈内存上,因此本身是自动回收的

(3)智能指针内部设计为当智能指针本身要被弹栈释放时,执行事先挂接好的清理函数

(4)智能指针的正常使用通过一些提供的方法和运算符重载来使用

struct pB
{
	int *p;
	int n;//记录使用的次数
	函数指针;//指向一个清理函数
}

简单指针 int *p1; 出错一般不是p1本身出错,而是其所指向的那块内存出错。

4、智能指针总结
(1)智能指针是普通指针的升级版,封装版,本身具备指针的功能,且多出一些自动释放资源机制。占用的内存多余普通指针。

(2)智能指针进行动态内存管理,要比普通指针多出很多(内存和性能上的)开销。

(3)智能指针的实现不是唯一的,C++有很多智能指针,各有优劣和适用场景,如:

std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::scoped_array、boost::shared_array、boost::weak_ptr、boost::intrusive_ptr。

(4)智能指针也要按照设计去正确使用,否则也会出问题。具体用法后续文章再讲。

五、Java的垃圾回收机制

1、Java语言整体框架
(1)CPU->操作系统内核->应用层框架->JVM(java虚拟机)->Java字节码->Java源代码

Java虚拟机是java语言的运行环境,Java字节码是java自己定义的一种格式,与任何CPU的机器码都不对应,是虚拟出来的一种机器语言,其在任何CPU和操作系统上都无法直接运行,必须放在java的虚拟机上运行。

android与windows的虚拟机并不兼容。

Java与C++不在一个层次上,C++在应用层框架,Java运行在java的虚拟机上。

(2)Java是解释型语言,而非编译型语言

(3)Java虚拟机是Java语言的运行时环境,也是Java语言跨平台的关键

2、Java的垃圾回收机制介绍
(1)什么是垃圾?
待回收的内存资源(主要指动态内存),本质是生命周期结束了的变量对象等。

(2)谁来回收?
GC线程,Java虚拟机中的守护线程。

(3)什么时候回收?
GC机制和算法来决定,程序员不用管。

(4)如何确定谁是垃圾?
引用计数法和可达性分析法。
介绍见:https://www.cnblogs.com/jiangtunan/p/11025521.html

引用计数法:
引用计数法就是给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加 1;当引用失效,计数器就减 1;任何时候计数器为 0 的对象就是不可能再被使用的,可以当做垃圾收集。这种方法实现起来很简单而且优缺点都很明显。

优点 执行效率高,程序执行受影响较小

缺点 无法检测出循环引用的情况,导致内存泄露

可达性分析算法:
这个算法的基本思想就是通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的。

3、垃圾回收机制点评
(1)不止java,其他语言如C#也是类似设计理念,典型特征就是语言没有指针的概念

(2)垃圾回收机制让程序员免于考虑对象的生命周期和资源的申请与释放,编程难度大减。

(3)垃圾回收机制的稳定性和效率取决于运行时环境(JVM等)设计和实现的好坏

(4)垃圾回收机制用效率和内存资源成本,换来了更简单不易错的语言特性。

应用了垃圾回收机制的语言没有指针

4、最后的总结
(1)本篇文章主要讲了C/C++/Java等语言的内存管理策略,尤其是动态内存管理策略

(2)机制本身有优点就有缺点,没有绝对好坏,适合的场景使用适合的机制才是上策

(3)C++掌握好以后再学习Java、Python等就简单多了

注:本资料大部分由朱老师物联网大讲堂课程笔记整理而来,如有侵权,联系删除!水平有限,如有错误,欢迎各位在评论区交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小嵌同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值