【Rust自学】4.1. 所有权:栈内存 vs. 堆内存

embedded/2024/12/21 22:06:24/

4.1.0 写在正文之前

在学习了Rust的通用编程概念后,就来到了整个Rust的重中之重——所有权,它跟其他语言都不太一样,很多初学者觉得学起来很难。这个章节就旨在让初学者能够完全掌握这个特性。

本章有三小节:

  • 所有权:栈内存 vs. 堆内存(本文)
  • 所有权规则、内存与分配
  • 所有权与函数

喜欢的话记得点赞、收藏加关注哦,想要跟着学下去记得关注专栏哦

4.1.1. 什么是所有权

所有权是Rust最独特的特性,它让Rust无需GC(垃圾收集器)就可以保证内存安全。

所有程序在运行时都必须管理它们使用计算机内存的方式。有的语言依靠垃圾收集机制,在程序运行时,它们会不断寻找不在使用的内存(比如C#);在其他语言中,程序员必须显式地分配和释放内存(比如C/C++)。

Rust不同于前两种。Rust使用所有权系统来管理内存,这个系统里还有一套规则,而编译器在编译时就会检查这套规则,而且这种做法不会产生任何的运行时开销。也就是说,在程序运行时,这种所有权特性不会减慢程序运行的速度,因为Rust把内存管理相关工作都提前到了编译时。

4.1.2. 栈内存(Stack) vs. 堆内存(Heap)

一般来说,程序员不会经常考虑栈内存与堆内存之间的区别。对于Rust这样的系统级编程语言来说,一个值它是在栈内存上还是在堆内存上对语言的行为和你要做的某些决定是由更大影响的。

在代码运行时,栈内存和堆内存都是可用的内存,但他们的结构很不相同。

4.1.3. 存储数据

1. 栈内存

栈内存按值的接收顺序来存储,按相反的顺序来将他们移除(后进先出,Last In First Out,简写为LIFO)。

添加数据叫压入栈(压栈),移除数据叫弹出栈(出栈)。

所有存储在栈内存上的数据必须拥有已知的固定的大小。 相反的,编译时大小未知的数据或是运行时大小可能发生变化的数据必须存放在堆内存上。

2. 堆内存

堆内存的的内存组织性差一些。当把数据放入堆内存时,会请求一定的空间。操作系统会在堆内存中找到一块足够大的空间,把它标记为在用,并返回一个指针,也就是这个空间的地址。这个过程叫做在Heap上进行内存分配,有时简称为"分配"。

3. 指针与内存

因为指针是固定大小的,可以把指针放在栈内存上。但如果想要指针所指向的具体数据时,就必须得使用指针所指向的地址来访问它。、

把数据压到栈内存上比在堆内存上分配要快得多

  • 在栈内存上,操作系统不需要寻找用来存储新数据的空间,那个位置永远都在栈内存的顶端(栈内存的末尾位置,也就是当前可用的栈内存的起始位置)。

  • 在堆内存上分配空间则需要做更多的工作:操作系统首先需要找到一个足够大的空间来存放数据,然后要做好记录方便下一次的分配。

4.1.4. 访问数据

访问栈内存中的数据要比访问堆内存中的数据快,因为需要通过指针才能找到堆内存中的数据,多了指针跳转这么一个环节,它属于间接的访问。而对于现代的处理器来说,由于缓存的缘故,如果指令在内存中跳转的数据越少,那么速度就越快。

如果数据存放的距离比较近,那么处理器的处理速度就会更快一些,例如放在栈内存上;反之,如果数据之间距离较远,那么处理速度就会慢一些,例如放在堆内存上(在堆内存上分配大量的空间也是需要时间的)。

4.1.5. 函数调用

当代码调用函数时,值被传入函数(也包括指向堆内存的指针)。函数本地的变量被压在栈内存上。当函数结束后,这些值会从栈内存上弹出。

4.1.6. 所有权存在的原因

所有权解决的问题:

  • 跟踪代码中分配的堆内存空间,换句话说就是跟踪代码的哪些部分正在使用堆内存的哪些数据
  • 最小化堆内存上的重复数据量
  • 清理堆内存上未使用的数据以避免空间不足

一旦懂了所有权,就不用经常地去想堆内存和栈内存了。但是知道管理堆内存数据是所有权存在的原因有助于解释它为什么会这样工作。


http://www.ppmy.cn/embedded/147641.html

相关文章

数据压缩比 38.65%,TDengine 重塑 3H1 的存储与性能

小T导读:这篇文章是“2024,我想和 TDengine 谈谈”征文活动的三等奖作品之一。作者通过自身实践,详细分享了 TDengine 在高端装备运维服务平台中的应用,涵盖架构改造、性能测试、功能实现等多个方面。从压缩效率到查询性能&#x…

什么是微端游戏?微端应该选择什么配置的服务器?

……微端网游就是游戏微型客户端,通过极小的微客户端的下载,运行,实现游戏可短时间正常运行,并实现边下边玩,从而解决大多数网络游戏完全客户端较大,用户下载安装时间长,登录用户低的问题&#…

MongoDB(上)

MongoDB 基础 MongoDB 是什么? MongoDB 是一个基于 分布式文件存储 的开源 NoSQL 数据库系统,由 C 编写的。MongoDB 提供了 面向文档 的存储方式,操作起来比较简单和容易,支持“无模式”的数据建模,可以存储比较复杂…

解决 OpenCV 与 FFmpeg 版本不兼容导致的编译错误

解决 OpenCV 与 FFmpeg 版本不兼容导致的编译错误 在安装并编译 OpenCV 3.2.0 版本时,出现的编译错误主要是由于 OpenCV 代码中使用的 FFmpeg 库宏定义与最新版 FFmpeg 库中的定义不一致所致。具体来说,原有的宏 CODEC_FLAG_GLOBAL_HEADER 和 AVFMT_RAW…

iOS 核心动画

核心动画 Layer 的自定义动画Layer 自带的仿射动画UIView 隐式动画显式动画CAPropertyAnimation CABasicAnimation repeatCounttimingFunctionfillModedelegate常见的 keyPathCASpringAnimationCAKeyframeAnimation cacluationModerotationMode沿路径的动画CATransitionUIView …

javaEE-多线程编程-3

目录 java 常见的包 : 回调函数: 什么是线程: 第一个线程: 验证多线程执行: 内核: 调用sleep()方法: 执行结果分析: 线程创建的几种方式: 1.继承Thread类,重写run()方法. 2.实现Runnable接口,重写run()方法. 3.继承Thread类,重写run()方法.但使用匿名内部类 4.实现…

利用git上传项目到GitHub

GitHub是基于git实现的代码托管。git是目前最好用的版本控制系统了,非常受欢迎,比之svn更好。 GitHub可以免费使用,并且快速稳定。 利用GitHub,你可以将项目存档,与其他人分享交流,并让其他开发者帮助你一…

lshw学习——简单介绍

文章目录 简介核心结构扫描设备原理scan_abiscan_burnerscan_cdromscan_cpufreqscan_cpuidscan_cpuinfoscan_device_treescan_diskscan_displayscan_dmiscan_fatscan_fbscan_graphicsscan_idescan_ideraidscan_inputscan_isapnpscan_lvmscan_memoryscan_mmcscan_mountsscan_net…