【Rust自学】4.1. 所有权:栈内存 vs. 堆内存
4.1 所有权栈内存 vs. 堆内存4.1.0 写在正文之前在学习了 Rust 的通用编程概念后就来到了整个 Rust 的重中之重——所有权。它跟其他语言都不太一样很多初学者觉得学起来很难。这个章节就旨在让初学者能够完全掌握这个特性。本章有五小节-所有权栈内存 vs. 堆内存本文- 所有权规则、内存与分配- 所有权与函数- 引用与借用- 切片Slice4.1.1 什么是所有权所有权是 Rust最独特的特性。它让 Rust 无需 GC垃圾收集器就可以保证内存安全。所有程序在运行时都必须管理它们使用计算机内存的方式。有的语言依靠垃圾收集机制在程序运行时它们会不断寻找不再使用的内存比如 C#。在其他语言中程序员必须显式地分配和释放内存比如 C/C。Rust 不同于前两种。Rust 使用所有权系统来管理内存。这个系统里还有一套规则而编译器在编译时就会检查这套规则。这种做法不会产生任何运行时开销。也就是说在程序运行时这种所有权特性不会减慢程序运行的速度因为 Rust 把内存管理相关工作都提前到了编译时。4.1.2 栈内存Stackvs. 堆内存Heap一般来说程序员不会经常考虑栈内存与堆内存之间的区别。对于 Rust 这样的系统级编程语言来说一个值是在栈内存上还是在堆内存上对语言的行为和你要做的某些决定有更大影响。在代码运行时栈内存和堆内存都是可用的内存但它们的结构很不相同。4.1.3 存储数据1. 栈内存栈内存按值的接收顺序来存储按相反的顺序来将它们移除后进先出Last In First Out简写为LIFO。添加数据叫压入栈push移除数据叫弹出栈pop。所有存储在栈内存上的数据必须拥有已知的、固定的大小。相反编译时大小未知的数据或运行时大小可能发生变化的数据必须存放在堆内存上。2. 堆内存堆内存的组织性差一些。当把数据放入堆内存时会请求一定的空间。操作系统会在堆内存中找到一块足够大的空间把它标记为在用并返回一个指针也就是这个空间的地址。这个过程叫做在堆上进行内存分配有时简称为“分配”。3. 指针与内存因为指针是固定大小的可以把指针本身放在栈内存上。但如果想要指针所指向的具体数据就必须使用指针中的地址来访问它。把数据压到栈内存上比在堆内存上分配要快得多- 在栈内存上操作系统不需要寻找用来存储新数据的空间那个位置永远都在栈内存的顶端栈内存的末尾——也就是当前可用的栈内存的起始位置。- 在堆内存上分配空间则需要做更多的工作操作系统首先需要找到一个足够大的空间来存放数据然后要做好记录方便下一次分配。4.1.4 访问数据访问栈内存中的数据要比访问堆内存中的数据快因为需要通过指针才能找到堆内存中的数据——多了一层间接访问。对于现代处理器来说由于缓存的缘故内存访问需要跳转的次数越少速度往往就越快。如果数据存放得比较近处理器的处理速度就会更快一些——例如放在栈内存上。反之如果数据之间距离较远处理速度就会慢一些——例如放在堆内存上在堆内存上分配大量空间也需要时间。4.1.5 函数调用当代码调用函数时值被传入函数也包括指向堆内存数据的指针。函数的局部变量被压到栈内存上。当函数结束后这些值会从栈内存上弹出。4.1.6 所有权存在的原因所有权解决的问题- 跟踪代码分配的堆内存——换句话说就是跟踪代码的哪些部分正在使用堆内存上的哪些数据- 最小化堆内存上的重复数据- 清理堆内存上未使用的数据以避免空间不足一旦懂了所有权就不用经常去想栈内存和堆内存了。但是知道管理堆数据是所有权存在的原因有助于解释它为什么会这样工作。