【Rust自学】4.1. 所有权:栈内存 vs. 堆内存
2026/7/23 18:46:52 网站建设 项目流程

4.1 所有权:栈内存 vs. 堆内存

4.1.0 写在正文之前

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

本章有五小节:
-所有权:栈内存 vs. 堆内存(本文)
- 所有权规则、内存与分配
- 所有权与函数
- 引用与借用
- 切片(Slice)

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)。

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

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

2. 堆内存

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

3. 指针与内存

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

把数据压到栈内存上比在堆内存上分配要快得多
- 在栈内存上,操作系统不需要寻找用来存储新数据的空间;那个位置永远都在栈内存的顶端(栈内存的末尾)——也就是当前可用的栈内存的起始位置。
- 在堆内存上分配空间则需要做更多的工作:操作系统首先需要找到一个足够大的空间来存放数据,然后要做好记录,方便下一次分配。

4.1.4 访问数据

访问栈内存中的数据要比访问堆内存中的数据快,因为需要通过指针才能找到堆内存中的数据——多了一层间接访问。对于现代处理器来说,由于缓存的缘故,内存访问需要跳转的次数越少,速度往往就越快。

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

4.1.5 函数调用

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

4.1.6 所有权存在的原因

所有权解决的问题:
- 跟踪代码分配的堆内存——换句话说,就是跟踪代码的哪些部分正在使用堆内存上的哪些数据
- 最小化堆内存上的重复数据
- 清理堆内存上未使用的数据,以避免空间不足

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询