【问题标题】:Is a String array e.g. [String; 3] stored on the stack or heap?是一个字符串数组,例如[细绳; 3] 存放在栈上还是堆上?
【发布时间】:2017-11-08 12:22:50
【问题描述】:

Rust 书规定:

另一个使堆栈快速的特性是堆栈上的所有数据都必须占用一个已知的固定大小。

它还说String 存储在堆上,因为大小未知并且可以变异。

“复合”数据结构(例如包含String 的数组)存储在哪里?数组的大小是固定的,但是数组的组件可以改变大小。

let array: [String; 3] = ["A","B","C"];

这种“复合”数据类型的存储位置的规则是什么?

【问题讨论】:

    标签: rust


    【解决方案1】:

    两者


    一个术语:在讨论一个类型的内存布局时,不应该谈论stack vs heap,而应该谈论inline vs offline1:

    • inline 表示数据就在这里,
    • 离线意味着数据在指针后面(无论它指向哪里)都可用。

    一个简单的例子,整数是内联存储的:

    //  i32
    +---+
    | 3 |
    +---+
    

    一个典型的struct Point { x: i32, y: i32 }也内联存储:

    //  Point
    +---+---+
    | x | y |
    +---+---+
    

    String,通常表示为 struct String { data: *mut u8, len: usize, cap: usize } 在线和离线存储:

    //   String
    +-------+-------+-------+
    | data  |  len  |  cap  |
    +-------+-------+-------+
        |
         \
          +-------------+
          |Hello, World!|
          +-------------+
    

    inline 部分是 3 个指针的存储空间,offline 部分是堆分配的记录,这里包含字符串 "Hello, World!" 的内容。

    然而,inline 并不总是意味着 stack。一个Box<Point>

    //  Box<Point>
    +-------+
    | data  |
    +-------+
        |
         \
          +---+---+
          | x | y |
          +---+---+
    

    将其Point(内联存储其数据成员)存储在堆上!

    同样,离线并不总是意味着

    fn main() {
        let i = 3;
        let r = &i;
    }
    

    这里r是一个引用(指针),它指向i,而i在栈上!

    1是的,我正在编造,更好的条款将不胜感激。


    那么,回到问题:

    它还说String 存储在堆上,因为大小未知并且可以变异。

    这是一个近似值,如上所述,String 有一些数据内联(指针、长度和容量)和一些在堆上(字符串内容)。

    “复合”数据结构(例如包含String 的数组)存储在哪里?数组的大小是固定的,但是数组的组成部分可以改变大小。

    let array: [String; 3] = ["A","B","C"];
    

    它同时存储在堆栈和堆中:

    //  [String; 3]
    +-------+-------+-------+-------+-------+-------+-------+-------+-------+
    | data  |  len  |  cap  | data  |  len  |  cap  | data  |  len  |  cap  |
    +-------+-------+-------+-------+-------+-------+-------+-------+-------+
        |                       |                       |    
         \                       \                       \
          +-+                     +-+                     +-+
          |A|                     |B|                     |C|
          +-+                     +-+                     +-+
    

    这是 9 个指针的内联数据(在堆栈上),以及堆上的 3 个单独分配。

    这种“复合”数据类型的存储位置的规则是什么?

    数据成员总是内联,指针和引用可能指向离线数据,这些数据可能在堆上,在栈上等等......

    【讨论】:

    • 一个后续,字符串数组的“数据”组件是彼此相邻存储还是在内存中的不同位置?也就是说,它是否连续?
    • @Greg:我不清楚您在说什么,尽管您似乎是指这 3 个字符串的内容(由data 指向)。如果是这种情况,那么它们将存储在 3 个单独的堆分配中,并且这些最终是否连续取决于分配器;当然不能保证,这就是我分开画它们的原因。
    • 谢谢,我说的正是这个
    【解决方案2】:

    String 只是包装了Vec&lt;u8&gt;。所以这适用于所有Vecs

    Vec 在堆栈上具有固定大小:它是长度、容量和指向存储实际内容的堆的指针。

    因此,在堆栈上有一个由三个Strings 组成的数组意味着这些字符串的“元数据”在堆栈上(长度、容量和指向数据的指针)。

    这些字符串的实际数据存储在堆中,因为您正确识别它的长度是可变的。

    【讨论】:

    • 另外,这里有一个Vec type guarantees的链接,描述了它的分配规则。
    • 我觉得这个答案比选的要简洁很多
    猜你喜欢
    • 2014-04-01
    • 2011-10-07
    • 2012-09-12
    • 2015-07-26
    • 2013-03-07
    • 2016-12-27
    • 2010-11-06
    • 2019-12-02
    • 2021-08-09
    相关资源
    最近更新 更多