Memory 当第二维度的大部分为空时,可空向量的内存效率最高的数组是什么?

Memory 当第二维度的大部分为空时,可空向量的内存效率最高的数组是什么?,memory,rust,Memory,Rust,我有一个很大的固定大小数组,其中包含u32的可变大小数组。大多数二维数组将为空(即,第一个数组将稀疏填充)。我认为Vec是最适合这两个维度的类型(Vec)。因为我的第一个数组可能相当大,所以我想找到最节省空间的方法来表示它 我看到两种选择: 我可以使用Vec。我猜想,由于选项是一个标记的并集,这将导致每个单元格被sizeof(Vec)四舍五入到标记的下一个单词边界 我可以直接为所有单元格使用Vec::with_capacity(0)。空的Vec在使用前是否分配零堆 哪个是最节省空间的方法?实际上

我有一个很大的固定大小数组,其中包含
u32
的可变大小数组。大多数二维数组将为空(即,第一个数组将稀疏填充)。我认为
Vec
是最适合这两个维度的类型(
Vec
)。因为我的第一个数组可能相当大,所以我想找到最节省空间的方法来表示它

我看到两种选择:

  • 我可以使用
    Vec
    。我猜想,由于
    选项
    是一个标记的并集,这将导致每个单元格被
    sizeof(Vec)
    四舍五入到标记的下一个单词边界

  • 我可以直接为所有单元格使用
    Vec::with_capacity(0)
    。空的
    Vec
    在使用前是否分配零堆

  • 哪个是最节省空间的方法?

    实际上,
    Vec
    Vec
    具有相同的空间效率

    ,因此编译器足够聪明,可以识别在
    选项
    的情况下,它可以通过在指针字段中输入0来表示
    。包含更多信息

    指针指向的后备存储器呢?使用
    Vec::new
    Vec::with_capacity(0)
    创建时(与第一个链接相同);在这种情况下,它使用一个特殊的、非空的“空指针”
    Vec
    仅在推送某个内容或以其他方式强制其分配时才在堆上分配空间。因此,用于
    Vec
    本身及其备份存储的空间是相同的。

    Vec
    是一个不错的起点。每个条目花费3个指针,即使它是空的,并且对于已填充的条目,每个分配开销可能会增加。但是,根据您愿意做出的权衡,可能会有更好的解决方案

    • Vec
      这将条目的大小从3个指针减少到2个指针。缺点是更改框中元素的数量既不方便(转换为和转换为
      Vec
      ),也更昂贵(重新分配)
    • HashMap
      如果外部集合足够稀疏,这将节省大量内存。缺点是更高的访问成本(散列、扫描)和更高的每元素内存开销
    • 如果集合只填充一次,并且您从未调整内部集合的大小,则可以使用拆分数据结构:

      这不仅将每个条目的大小减少到1个指针,还消除了每个分配的开销

      struct Nested<T> {
         data: Vec<T>,
         indices: Vec<usize>,// points after the last element of the i-th slice
      }
      
      impl<T> Nested<T> {
          fn get_range(&self, i: usize) -> std::ops::Range<usize> {
             assert!(i < self.indices.len());
             if i > 0 {
                 self.indices[i-1]..self.indices[i]
              } else {
                 0..self.indices[i]
              }
          }
      
          pub fn get(&self, i:usize) -> &[T] {
              let range = self.get_range(i);
              &self.data[range]
          }
      
          pub fn get_mut(&mut self, i:usize) -> &mut [T] {
              let range = self.get_range(i);
              &mut self.data[range]
          }
      }
      
      struct嵌套{
      资料来源:Vec,
      索引:Vec,//第i个切片最后一个元素后的点
      }
      嵌套的{
      fn获取范围(&self,i:usize)->std::ops::range{
      断言!(i0{
      自索引[i-1]…自索引[i]
      }否则{
      0.自索引[i]
      }
      }
      pub fn get(&self,i:usize)->和[T]{
      让范围=自我。获取范围(i);
      &self.data[范围]
      }
      pub fn get_mut(&mut self,i:usize)->&mut[T]{
      让范围=自我。获取范围(i);
      &多个自身数据[范围]
      }
      }
      
      为了节省更多内存,您可以将索引减少到
      u32
      ,将每个集合的元素数限制在40亿个


    我猜…-为什么不直接用它来找出尺码呢?谢谢!考虑到我对这门语言还很陌生,我仍然很感激能将这些点连接起来的确认。这是利用稀疏性的好主意!我特别喜欢第三种选择。我怀疑对于第二种方法,
    BTreeMap
    可能比
    HashMap
    更好,尤其是在需要按顺序遍历的情况下。