MST

星途 面试题库

面试题:Rust中复杂数据结构的内存分配

假设有一个自定义的Rust结构体,其中包含多个不同类型的成员,包括Vec<T>和自定义的其他结构体。请详细描述在创建该结构体实例时,栈内存和堆内存是如何分配的,以及所有权和生命周期在这个过程中是如何影响内存分配的。
46.1万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试
  1. 栈内存和堆内存分配
    • 栈内存
      • 对于结构体中所有基础类型(如i32bool等)的成员,它们会直接存储在栈上。例如,如果结构体有一个i32类型的成员numnum的值会直接存储在栈上结构体实例的内存空间内。
      • 对于Vec<T>类型的成员,Vec本身是一个胖指针(fat pointer),它由三个部分组成:指向堆上数据的指针、长度和容量。这三个部分会存储在栈上,而实际存储T类型元素的数据块会在堆上分配。
      • 对于自定义结构体类型的成员,如果这个自定义结构体只包含基础类型成员,那么整个自定义结构体实例会像基础类型一样存储在栈上。例如,如果有一个自定义结构体Inner { field: i32 },并且外部结构体包含Inner类型的成员,Inner实例会直接存储在栈上外部结构体实例的内存空间内。
    • 堆内存
      • Vec<T>类型成员实际存储元素的数据块在堆上分配。例如,Vec<i32>会在堆上分配一块连续的内存来存储i32元素。如果Vec的长度为n,会在堆上分配n * size_of::<i32>()大小的内存空间。
      • 如果自定义结构体成员包含Vec<T>或其他需要堆分配的数据结构,那么这些部分会在堆上分配。例如,自定义结构体Inner { vec: Vec<i32> }vec中的数据会在堆上分配,尽管Inner结构体实例可能存储在栈上(如果外部结构体在栈上创建)。
  2. 所有权和生命周期对内存分配的影响
    • 所有权
      • 当创建结构体实例时,结构体获得其成员的所有权。例如,对于Vec<T>成员,在Vec创建时就拥有了堆上存储元素数据块的所有权。如果将结构体实例赋值给另一个变量,整个结构体(包括其成员的所有权)会转移。例如:
struct MyStruct {
    vec: Vec<i32>,
}
let s1 = MyStruct { vec: vec![1, 2, 3] };
let s2 = s1; // s1不再拥有vec的所有权,所有权转移到s2
 - 对于自定义结构体成员,如果其内部有拥有所有权的数据结构(如`Vec`),那么外部结构体拥有整个自定义结构体成员的所有权,包括内部数据结构的所有权。
  • 生命周期
    • 结构体的生命周期至少要与其所有成员的生命周期一样长。例如,如果结构体有一个Vec<T>成员,Vec的生命周期不能超过结构体的生命周期。如果Vec在结构体之前被销毁,会导致悬空指针错误。
    • 对于包含自定义结构体成员的情况,如果自定义结构体有生命周期参数,外部结构体的生命周期需要考虑内部自定义结构体的生命周期。例如:
struct Inner<'a> {
    data: &'a i32,
}
struct Outer<'a> {
    inner: Inner<'a>,
}
let num = 42;
let inner = Inner { data: &num };
let outer = Outer { inner };

这里Outer结构体的生命周期依赖于Inner结构体,而Inner结构体的生命周期依赖于&'a i32引用的生命周期。Outer结构体的实例outer的生命周期不能超过num的生命周期,因为Inner中的引用指向num。当num被销毁时,outer也不能再安全使用。