在C++中计算某些内容的字节大小

gdx19jrr  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(80)

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

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:
这是计算其大小的正确方法:
它是每个保留(或使用)元素一个float和一个int加上每列两个int加上sizeof(Matrix)固定开销

fivyi3re

fivyi3re1#

正如在评论中所讨论的,这里我解释稀疏矩阵格式
您调用reserve(),因此特定的子格式是 uncompressed

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

这使得(2 * 2**25 * 26 * 4 + 2 * 2**25 * 4) / 1024**3 = 6.75 GiB
我们来测试一下

#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


如您所见,四个mmmap分配,总大小为7,247,773,696字节;即6.75 GiB。
这将在内存较少的笔记本电脑上工作的原因是,您还没有使用该内存。内存被Map,但没有初始化,因此操作系统将其全部Map到它为此目的而拥有的单个零页。参见例如Allocating more memory than there exists using malloc

范围关注点

需要注意的一点是,这种格式使用简单的int来表示非零元素的数组偏移量。这意味着非零(和保留元素)的总数必须保持在2**31-1(有符号int范围)以下。使用2**25 * 26元素,您已经接近2**30元素。
除非你知道这是绝对的上限,不考虑增长,否则我建议你将格式改为Eigen::SparseMatrix<float, Eigen::ColMajor, Eigen::Index>,使用Eigen::Index,也就是std::ptrdiff_t,而不是int。这将使内存使用量增加到大约10.25 GiB,但它将消除所有关于潜在整数溢出的担忧。

相关问题