在 C++ 中计算某些内容的大小(以字节为单位)

Evaluate the size in bytes of something in C++

提问人:Matteo 提问时间:11/15/2023 最后编辑:Matteo 更新时间:11/16/2023 访问量:186

问:

我有一个来自特征库的稀疏矩阵,定义为:

Eigen::SparseMatrix<float> MyMatrix(2**n, 2**n). 

此外,我还使用了功能保留:

MyMatrix.reserve(Eigen::VectorXi::Constant(2**n, n+1)); 

该矩阵每列有 n+1 个非零数,它有 2^n 列

我想要这个对象占用的实际大小(以字节为单位)。

如果我使用:

MyMatrix.size()

它给出 n_rows*n_columns。

我确定它不是存储的实际大小,因为我检查了计算机的内存。

例如,我可以用这种方式在我的计算机上创建一个 2^25 * 2^25 稀疏大小的浮点数矩阵,它应该占用 ~ 10^15 字节,这根本不可能。

如果我写

sizeof(MyMatrix) 

它给出 72,无论我使用哪一个 n。它可能与类本身有关,而不是实际保存在其中的对象

更新2:

这是计算其大小的正确方法:

它是每个保留(或使用)元素的一个浮点数和一个 int 加上每列两个 int 加上 sizeof(Matrix) 固定开销

C++ 稀疏矩阵 大小特征类

评论

8赞 user4581301 11/15/2023
sizeof是一个编译时运算符,它始终为您提供应用它的对象的大小(以字节为单位)。对于包含指针的对象,它所能考虑的只是指针的大小。它不知道,就像指针一样,不知道物体指向有多大。
3赞 Igor Tandetnik 11/15/2023
MyMatrix.nonZeros()将为您提供非零元素的数量。内存要求应大致与此成正比。
13赞 Peter 11/15/2023
^不是 C++ 中的幂(幂)运算符。
7赞 Jesper Juhl 11/15/2023
^表示在 C++ 中,而不是幂。xor
1赞 Homer512 11/15/2023
例如,我在这里解释了 Eigen 的稀疏格式。它是每个保留(或使用的)元素的一个浮点数和一个 int 加上每列两个 int 加上固定开销sizeof(Matrix)

答:

1赞 Homer512 11/16/2023 #1

正如评论中所讨论的,这里我将解释稀疏矩阵格式

调用 ,因此特定的子格式是未压缩的。这意味着我们有reserve()

  • 每个非零条目或保留条目 1 个浮点数 (2**25 * 26 * 4 byte)
  • 每个非零条目或保留条目 1 int(同上)
  • 每列 1 int,表示上述两个向量中该列的第一个非零条目的起始偏移量 (2**25 * 4 byte)
  • 每列 1 int 用于结束(同上)

这给了我们 = 6.75 GiB(2 * 2**25 * 26 * 4 + 2 * 2**25 * 4) / 1024**3

让我们来测试一下:

#include <Eigen/Dense>
#include <Eigen/Sparse>

#include <malloc.h>


int main()
{
  int size = 1<<25;
  int nonzero_per_row = 26;
  Eigen::SparseMatrix<float> mat(size, size);
  mat.reserve(Eigen::VectorXi::Constant(size, nonzero_per_row));
  malloc_stats();
}

这将打印:

Arena 0:
system bytes     =     135168
in use bytes     =      74400
Total (incl. mmap):
system bytes     = 2952941568
in use bytes     = 2952880800
max mmap regions =          4
max mmap bytes   = 7247773696

如您所见,四个映射分配的总大小为 7,247,773,696 字节;即 6.75 GiB。

这将在内存较少的笔记本电脑上运行的原因是您还没有使用该内存。内存是 mmapped,但未初始化,因此操作系统将其全部映射到它为此目的而拥有的单个零页。例如,请参阅使用 malloc 分配比现有内存更多的内存

整数范围问题

应该注意的一件事是,这种格式使用一个简单的来表示非零元素的数组偏移量。这意味着非零(和保留元素)的总数必须保持在(有符号范围)以下。有了元素,你就已经接近元素了。int2**31-1int2**25 * 262**30

除非您知道这是绝对的上限,而不考虑增长,否则我建议您将格式更改为 ,使用 ,又名 ,而不是 。这会将内存使用量提高到大约 10.25 GiB,但它将消除对潜在整数溢出的所有担忧。Eigen::SparseMatrix<float, Eigen::ColMajor, Eigen::Index>Eigen::Indexstd::ptrdiff_tint