Rust内存和分配

737 阅读3分钟

这是我参与11月更文挑战的第23天,活动详情查看:2021最后一次更文挑战

内存与分配

上一篇文章最后留了一个小问题,为什么String类型可变而字面值却不行呢?区别就在于两种数据类型对内存的处理上。

就字符串字面值而言,在编译的时候就知道其内容是什么,因此文本被直接硬编码进最终的可执行文件中,这使得字符串字面值快速高效,但是这些特性都是基于字符串字面值的不可变性。开发人员如果想实现每一个在编译时大小未知的文本而将一块内存放入二进制文件中,并且它的大小还可能随着程序运行而改变这是无法实现的。

对于String类型而言,为了支持一个可变,可增长的文本片段,需要在堆上分配一块在编译时未知大小的内存来存放内容。这意味着:

  • 在程序运行时需要向操作系统请求内存;

  • 需要一个当我们处理完String时将内存返回给操作系统的方法

上面的第一部分由开发人员完成,当调用String::from时,就会向操作系统请求所需要的内存,这在编程语言中是非常通用的。

但是第二部分实现起来就各有区别了,在有 垃圾回收garbage collectorGC)的语言中, GC 记录并清除不再使用的内存,所以开发人员并不需要关心它。但是如果没有 GC 的话,识别出不再使用的内存并调用代码显式释放就是开发人员的责任了,跟请求内存的时候一样。正确处理内存回收曾经是一个困难的编程问题,如果忘记回收了会浪费内存。如果过早回收了,将会出现无效变量。如果重复回收,这也是个 bug。我们需要精确的为一个 allocate 配对一个 free

Rust采用了一个不同的策略,拥有某块内存的变量,当这个变量离开其作用域之后就会被自动释放。

fn main() {
    // i 在还没有声明的时候是无效的
    let i = "rust";  // 从此处起,i 是有效的
    
    println!("{}", i); // 可以对i变量进行操作
}
// i 作用域到此结束,i 不再有效

这是一个将String需要的内存返回给操作系统的很自然的位置,当i离开其作用域的时候,Rust 就会自动调用一个特殊的函数drop,该函数可以释放离开作用域的变量所占用的内存。

这种模式对编写Rust代码有深远的影响,虽然看起来简单,但是在更复杂的场景下代码的行为可能是不可预测的,比如当有多个变量使用在堆上分配的内存时。对于这些场景,作者将单独另写一篇文章哦~

结语

文章首发于微信公众号程序媛小庄,同步于掘金

码字不易,转载请说明出处,走过路过的小伙伴们伸出可爱的小指头点个赞再走吧(╹▽╹)