提问人:Matteo 提问时间:11/15/2023 最后编辑:Matteo 更新时间:11/16/2023 访问量:186
在 C++ 中计算某些内容的大小(以字节为单位)
Evaluate the size in bytes of something in C++
问:
我有一个来自特征库的稀疏矩阵,定义为:
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) 固定开销
答:
正如评论中所讨论的,这里我将解释稀疏矩阵格式
调用 ,因此特定的子格式是未压缩的。这意味着我们有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 分配比现有内存更多的内存
整数范围问题
应该注意的一件事是,这种格式使用一个简单的来表示非零元素的数组偏移量。这意味着非零(和保留元素)的总数必须保持在(有符号范围)以下。有了元素,你就已经接近元素了。int
2**31-1
int
2**25 * 26
2**30
除非您知道这是绝对的上限,而不考虑增长,否则我建议您将格式更改为 ,使用 ,又名 ,而不是 。这会将内存使用量提高到大约 10.25 GiB,但它将消除对潜在整数溢出的所有担忧。Eigen::SparseMatrix<float, Eigen::ColMajor, Eigen::Index>
Eigen::Index
std::ptrdiff_t
int
评论
sizeof
是一个编译时运算符,它始终为您提供应用它的对象的大小(以字节为单位)。对于包含指针的对象,它所能考虑的只是指针的大小。它不知道,就像指针一样,不知道物体指向有多大。MyMatrix.nonZeros()
将为您提供非零元素的数量。内存要求应大致与此成正比。^
不是 C++ 中的幂(幂)运算符。^
表示在 C++ 中,而不是幂。xor
sizeof(Matrix)