我有一个存储float32对象的二进制文件(9748422 * 5)。从这样的集合(190MB大小),我创建了一组Eigen::VectorXd
向量(每个有5个组件),因此9748422。基础类型是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对其大多数动态向量使用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的浪费 - 完全合理且可能是可预测的)。
答案 0 :(得分:4)
你这里有很多指针,每个指针都有分配开销。指针指的是小对象,因此开销很大。
最重要的是,动态分配的对象必然比固定大小的对象具有更多的开销。这是因为固定大小的对象不需要存储矩阵维度。
以下是指针开销的来源:
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位代码。
答案 1 :(得分:2)
我不允许发表评论,所以我会再发一个答案,即使我认为上述答案实际上解释了浪费内存的来源(大量分配)。
据我所知,你想要使用很多penta,所以你使用的是结构SSCCE_struct的向量,即
std::vector<SSCCE_struct*> TVector;
您是否考虑过使用
Eigen::Matrix< double, Dynamic, 5 > outputVertices;
outputVertices.resize( noPoints, 5 );
这可以避免浪费内存。我也会考虑将其用于矢量化(以帮助特征/编译器更好地矢量化你用它们做的任何事情),即使5不是一个非常方便的矢量化数字,如4或8。
编辑:我意识到我点击帖子后的时间已经晚了3年......