【发布时间】:2014-04-08 08:59:26
【问题描述】:
我有一个存储 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);
}
}
稍后编辑:
我执行了大卫回答中指出的测试,解决方案是完全避免动态分配。您可以尝试多种组合,以下是所有这些组合的结果:
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 的浪费 - 完全合理,也许是可预测的)。
【问题讨论】:
-
aligned_alloc没有解释这一点。 SSCCE 会很好。你应该很容易做到。 -
@DavidHeffernan 我添加了一个pseudoSSCCE(恐怕不能那么容易地在线编译:D - 你需要数据、Eigen、winapi 等等)。
-
你不需要让它在线编译。一个示例输入文件也很好。无论如何,我想知道你为什么使用
VectorXd而不是Vector5d。后者肯定会更有效率。 -
这只是一个提示,但您可以使用
Eigen::Map和Eigen::Matrix<double,1,5>(或5,1ofc)交叉检查内存使用情况,以排除默认的特征动态分配器。 @DavidHeffernan 我不太确定。我认为 5 或 6 是他们衡量性能时的边界情况。他们建议对更长的向量使用动态。我可以检查参考文献,因为我对此记忆模糊,但我很确定我在某个地方读到过。 -
@luk32 对于内存,使用固定大小必须更有效。这样就可以避免堆分配开销。
标签: c++ winapi memory eigen allocator