rust学习(第二章)

前置知识

  1. 栈和堆
    什么数据放栈里,什么数据放堆里?
    我们以为的:
  • 基本类型(primitive type)存储在栈上,对象存储在堆上;
  • 少量数据存储在栈上,大量的数据存储在堆上。

事实是:

在编译时,一切无法确定大小或者大小可以改变的数据,都无法安全地放在栈上,最好放在堆上。

比如一个函数,参数是字符串:

bash 复制代码
fn say_name(name: String) {}

// 调用
say_name("Lindsey".to_string());
say_name("Rosie".to_string());

字符串的数据结构,在编译时大小不确定,运行时执行到具体的代码才知道大小。比如上面的代码,"Lindsey" 和 "Rosie" 的长度不一样,say_name() 函数只有在运行的时候,才知道参数的具体的长度。所以,我们无法把字符串本身放在栈上,只能先将其放在堆上,然后在栈上分配对应的指针,引用堆上的内存。

只需要改动栈指针(stack pointer),就可以预留相应的空间;把栈指针改动回来,预留的空间又会被释放掉。

预留和释放只是动动寄存器,不涉及额外计算、不涉及系统调用,因而效率很高。所以理论上说,只要可能,我们应该把变量分配到栈上,这样可以达到更好的运行速度。

那为什么在实际工作中,我们又要避免把大量的数据分配在栈上呢?

这主要是考虑到调用栈的大小,避免栈溢出(stack overflow)。

一旦当前程序的调用栈超出了系统允许的最大栈空间,无法创建新的帧,来运行下一个要执行的函数,就会发生栈溢出,这时程序会被系统终止,产生崩溃信息。

过大的栈内存分配是导致栈溢出的原因之一,更广为人知的原因是递归函数没有妥善终止。一个递归函数会不断调用自己,每次调用都会形成一个新的帧,如果递归函数无法终止,最终就会导致栈溢出。

栈虽然使用起来很高效,但它的局限也显而易见。当我们需要动态大小的内存时,只能使用堆,比如可变长度的数组、列表、哈希表、字典,它们都分配在堆上。

栈上的内存在函数调用结束之后,所使用的帧被回收,相关变量对应的内存也都被回收待用。所以栈上内存的生命周期是不受开发者控制的,并且局限在当前调用栈。而堆上分配出来的每一块内存需要显式地释放,这就使堆上内存有更加灵活的生命周期,可以在不同的调用栈之间共享数据。

然而,堆内存的这种灵活性也给内存管理带来很多挑战。

如果手工管理堆内存的话,堆上内存分配后忘记释放,就会造成内存泄漏。一旦有内存泄漏,程序运行得越久,就越吃内存,最终会因为占满内存而被操作系统终止运行。如果堆上内存被多个线程的调用栈引用,该内存的改动要特别小心,需要加锁以独占访问,来避免潜在的问题。

比如说,一个线程在遍历列表,而另一个线程在释放列表中的某一项,就可能访问野指针,导致堆越界(heap out of bounds)。而堆越界是第一大内存安全问题。如果堆上内存被释放,但栈上指向堆上内存的相应指针没有被清空,就有可能发生使用已释放内存(use after free)的情况,程序轻则崩溃,重则隐含安全隐患

小结

对于存入栈上的值,它的大小在编译期就需要确定。栈上存储的变量生命周期在当前调用栈的作用域内,无法跨调用栈引用。

堆可以存入大小未知或者动态伸缩的数据类型。堆上存储的变量,其生命周期从分配后开始,一直到释放时才结束,因此堆上的变量允许在多个调用栈之间引用。但也导致堆变量的管理非常复杂,手工管理会引发很多内存安全性问题,而自动管理,无论是 GC 还是 ARC,都有性能损耗和其它问题。

一句话对比总结就是:栈上存放的数据是静态的,固定大小,固定生命周期;堆上存放的数据是动态的,不固定大小,不固定生命周期。

相关推荐
iqay1 小时前
【C语言】填空题/程序填空题1
c语言·开发语言·数据结构·c++·算法·c#
字节全栈_kYu1 小时前
微信小程序视频点播在线视频学习系统 毕业设计 课程设计(1)首页_微信小程序视频功能设计流程图
学习·微信小程序·课程设计
想拿高薪的韭菜1 小时前
人工智能第2章-知识点与学习笔记
人工智能·笔记·学习
Future_yzx2 小时前
Java Web的发展史与SpringMVC入门学习(SpringMVC框架入门案例)
java·前端·学习
Future_yzx2 小时前
Spring MVC学习——发送请求(@RequestMapping注解及请求参数绑定)
学习·spring·mvc
makabaka_T_T2 小时前
25寒假算法刷题 | Day1 | LeetCode 240. 搜索二维矩阵 II,148. 排序链表
数据结构·c++·算法·leetcode·链表·矩阵
小菜鸟博士3 小时前
手撕Vision Transformer -- Day1 -- 基础原理
人工智能·深度学习·学习·算法·面试
wclass-zhengge3 小时前
04树 + 堆 + 优先队列 + 图(D1_树(D6_B树(B)))
数据结构·b树
美味小鱼4 小时前
初识Cargo:Rust的强大构建工具与包管理器
开发语言·rust·cargo
Bluesonli4 小时前
UE5 蓝图学习计划 - Day 6:角色蓝图
学习·ue5·unreal engine