我有一个存储 float32 对象(其中 9748422*5 个)的二进制文件。从这样的集合(大约 190MB)中,我创建了一组 Eigen::VectorXd
vector (每个有 5 个分量),因此有 9748422 个 vector 。底层类型是 double
,因此存储它们的输入大小大约加倍。
但是,幸运的是,该过程总共需要 2.5GB。这是 PROCESS_MEMORY_COUNTERS
的日志:
PageFaultCount: 0x000A3C40
PeakWorkingSetSize: 0xA3C42000
WorkingSetSize: 0xA3C42000
QuotaPeakPagedPoolUsage: 0x00004ED8
QuotaPagedPoolUsage: 0x00004ED8
QuotaPeakNonPagedPoolUsage: 0x000057A8
QuotaNonPagedPoolUsage: 0x000057A8
PagefileUsage: 0xA3A9B000
PeakPagefileUsage: 0xA3A9B000
我跟踪了 Eigen 的内部分配器,它似乎确实“分配”了我在纸上计算的大小。然而,Eigen 对其大部分动态 vector 使用 aligned_alloc。这会造成如此大的破坏吗?如果什么都没有想到,您能否推荐另一个地方来寻找发生这种情况的问题?
我无法提供可编译的(在线)cpp 示例,但这是我正在做的事情的框架:
struct SSCCE_struct
{
Eigen::VectorXd m_data;
};
typedef std::vector<SSCCE_struct*> TVector;
int main(int argc, char* argv[])
{
TVector outputVertices;
HANDLE bpcHandle;
bpcHandle = CreateFileA("D:\\sample.bpc",
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
LARGE_INTEGER len_li;
GetFileSizeEx (bpcHandle, &len_li);
INT64 len = len_li.QuadPart; //(len_li.u.HighPart << 32) | len_li.u.LowPart;
unsigned long long noPoints = len / 20;
unsigned long noPointsRead = 0;
unsigned long long currPointIdx = 0;
outputVertices.resize( noPoints );
DebugTrace( "No points %lu \n", noPoints );
float buffer[ 5 * 1024 ];
DWORD noBytesRead = 0;
do
{
ReadFile(bpcHandle, buffer, sizeof(buffer), &noBytesRead, NULL);
noPointsRead = noBytesRead / 20;
for (unsigned long idx = 0; idx < noPointsRead; ++idx )
{
outputVertices[ currPointIdx + idx ] = new SSCCE_struct();
outputVertices[ currPointIdx + idx ]->m_data.resize(5);
for (unsigned kdx = 0; kdx < 5; ++kdx)
{
outputVertices[ currPointIdx + idx ]->m_data[ kdx ] = buffer[ 5 * idx + kdx ];
}
}
currPointIdx += noPointsRead;
} while (noBytesRead);
CloseHandle(bpcHandle);
}
}
稍后编辑:
我执行了 David 的回答中指示的测试,解决方案是完全避免动态分配。可以尝试多种组合,以下是所有组合的结果:
1.
struct SSCCE_struct
{
Eigen::Matrix<double,1,5> m_data;
};
typedef std::vector<SSCCE_struct*> TVector;
产生 1.4 GB(1.1 GB 浪费)
2.
struct SSCCE_struct
{
Eigen::VectorXd m_data;
};
typedef std::vector< SSCCE_struct* > TVector;
产生 2.5 GB(2.2 GB 浪费)
3.
struct SSCCE_struct
{
Eigen::Matrix<double,1,5> m_data;
};
typedef std::vector<SSCCE_struct> TVector;
产生 381 GB(有 40 MB 的浪费 - 完全合理,也许是可预测的)。
最佳答案
这里有很多指针,每个指针都有分配开销。指针指向小对象,因此开销很大。
最重要的是,动态分配的对象必然比固定大小的对象有更多的开销。那是因为固定大小的对象不需要存储矩阵维度。
以下是指针开销的来源:
-
Eigen::VectorXd
使用动态分配的存储。这意味着一个指针。 - 您将对象存储在
std::vector<SSCCE_struct*>
中.这是另一个指针,带有开销。
存储这些对象的最有效方法是删除间接寻址。您可以通过切换到:
-
Matrix<double, 5, 1>
.这是一个固定大小的对象,因此没有间接寻址。更重要的是,如上所述,它不需要在运行时存储矩阵维度,因为它们在编译时是已知的。对于如此重要的小物体。 - 将对象存储在
std::vector<SSCCE_struct>
中.同样,您失去了一个间接级别。
通过这些更改,当使用发布设置编译时,您的程序的内存使用量在我的机器上下降到 383MB。这更符合您的期望。
最大的区别似乎在Eigen::VectorXd
之间。和固定大小的对象。如果我使用 Eigen::VectorXd
和 std::vector<SSCCE_struct>
然后内存使用量跳到 918MB。当我然后去 std::vector<SSCCE_struct*>
它进一步跃升至 1185MB。
这些测量将高度依赖于编译器。我使用 VS2013 编译 32 位代码。
关于c++ - 动态 vector 的特征库内存使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22932260/