深入理解Rust所有权机制

本文详细解释了Rust编程语言中栈与堆的概念、性能差异以及所有权原则,强调了变量绑定背后的数据交互,包括转移所有权、深浅拷贝和函数传值。Rust通过所有权机制确保内存安全,避免内存泄漏和二次释放的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


  团队博客: 汽车电子社区


一、概述

  所有的程序都必须和计算机内存打交道,如何从内存中申请空间来存放程序的运行内容,如何在不需要的时候释放这些空间,成了重中之重,也是所有编程语言设计的难点之一。在计算机语言不断演变过程中,出现了三种流派:
    1、垃圾回收机制(GC),在程序运行时不断寻找不再使用的内存,典型代表:Java、Go。
    2、手动管理内存的分配和释放, 在程序中,通过函数调用的方式来申请和释放内存,典型代表:C++。
    3、通过所有权来管理内存,编译器在编译时会根据一系列规则进行检查。
  其中 Rust 选择了第三种,最妙的是,这种检查只发生在编译期,因此对于程序运行期,不会有任何性能上的损失。

二、栈(Stack)与堆(Heap)

  栈和堆是编程语言最核心的数据结构,但是在很多语言中,你并不需要深入了解栈与堆。 但对于 Rust 这样的系统编程语言,值是位于栈上还是堆上非常重要, 因为这会影响程序的行为和性能。
  栈和堆的核心目标就是为程序在运行时提供可供使用的内存空间。

2.1、栈

  栈按照顺序存储值并以相反顺序取出值,这也被称作后进先出。想象一下一叠盘子:当增加更多盘子时,把它们放在盘子堆的顶部,当需要盘子时,再从顶部拿走。不能从中间也不能从底部增加或拿走盘子!
  增加数据叫做进栈,移出数据则叫做出栈。
  因为上述的实现方式,栈中的所有数据都必须占用已知且固定大小的内存空间,假设数据大小是未知的,那么在取出数据时,你将无法取到你想要的数据。

2.2、堆

  与栈不同,对于大小未知或者可能变化的数据,我们需要将它存储在堆上。
  当向堆上放入数据时,需要请求一定大小的内存空间。操作系统在堆的某处找到一块足够大的空位,把它标记为已使用,并返回一个表示该位置地址的指针, 该过程被称为在堆上分配内存,有时简称为 “分配”(allocating)。
  接着,该指针会被推入栈中,因为指针的大小是已知且固定的,在后续使用过程中,你将通过栈中的指针,来获取数据在堆上的实际内存位置,进而访问该数据。
  由上可知,堆是一种缺乏组织的数据结构。想象一下去餐馆就座吃饭: 进入餐馆,告知服务员有几个人,然后服务员找到一个够大的空桌子(堆上分配的内存空间)并领你们过去。如果有人来迟了,他们也可以通过桌号(栈上的指针)来找到你们坐在哪。

2.3、性能区别

  **写入方面:**入栈比在堆上分配内存要快,因为入栈时操作系统无需分配新的空间,只需要将新数据放入栈顶即可。相比之下,在堆上分配内存则需要更多的工作,这是因为操作系统必须首先找到一块足够存放数据的内存空间,接着做一些记录为下一次分配做准备。
**加粗样式****读取方面:**得益于 CPU 高速缓存,使得处理器可以减少对内存的访问,高速缓存和内存的访问速度差异在 10 倍以上!栈数据往往可以直接存储在 CPU 高速缓存中,而堆数据只能存储在内存中。访问堆上的数据比访问栈上的数据慢,因为必须先访问栈再通过栈上的指针来访问内存。
  因此,处理器处理和分配在栈上数据会比在堆上的数据更加高效。

2.4、所有权与堆栈

  当你的代码调用一个函数时,传递给函数的参数(包括可能指向堆上数据的指针和函数的局部变量)依次被压入栈中,当函数调用结束时,这些值将被从栈中按照相反的顺序依次移除。
  因为堆上的数据缺乏组织,因此跟踪这些数据何时分配和释放是非常重要的,否则堆上的数据将产生内存泄漏 —— 这些数据将永远无法被回收。这就是 Rust 所有权系统为我们提供的强大保障。
  对于其他很多编程语言,你确实无需理解堆栈的原理,但是在 Rust 中,明白堆栈的原理,对于我们理解所有权的工作原理会有很大的帮助。

三、所有权原则

  理解了堆栈,接下来看一下关于所有权的规则,首先请谨记以下规则:
    1、Rust 中每一个值都被一个变量所拥有,该变量被称为值的所有者。
    2、一个值同时只能被一个变量所拥有,或者说一个值只能拥有一个所有者。
    3、当所有者(变量)离开作用域范围时,这个值将被丢弃(drop)。

3.1、变量作用域

  作用域是一个变量在程序中有效的范围, 假如有这样一个变量:

let s = "hello"

  变量 s 绑定到了一个字符串字面值,该字符串字面值是硬编码到程序代码中的。s 变量从声明的点开始直到当前作用域的结束都是有效的:

{
                         // s 在这里无效,它尚未声明
    let s = "hello";   // 从此处起,s 是有效的

    // 使用 s
}                      // 此作用域已结束,s不再有效

  简而言之,s 从创建伊始就开始有效,然后有效期持续到它离开作用域为止ÿ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值