c++ - 动态 vector 的特征库内存使用

标签 c++ winapi memory eigen allocator

我有一个存储 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 的浪费 - 完全合理,也许是可预测的)。

最佳答案

这里有很多指针,每个指针都有分配开销。指针指向小对象,因此开销很大。

最重要的是,动态分配的对象必然比固定大小的对象有更多的开销。那是因为固定大小的对象不需要存储矩阵维度。

以下是指针开销的来源:

  1. Eigen::VectorXd使用动态分配的存储。这意味着一个指针。
  2. 您将对象存储在 std::vector<SSCCE_struct*> 中.这是另一个指针,带有开销。

存储这些对象的最有效方法是删除间接寻址。您可以通过切换到:

  1. Matrix<double, 5, 1> .这是一个固定大小的对象,因此没有间接寻址。更重要的是,如上所述,它不需要在运行时存储矩阵维度,因为它们在编译时是已知的。对于如此重要​​的小物体。
  2. 将对象存储在std::vector<SSCCE_struct>中.同样,您失去了一个间接级别。

通过这些更改,当使用发布设置编译时,您的程序的内存使用量在我的机器上下降到 383MB。这更符合您的期望。

最大的区别似乎在Eigen::VectorXd之间。和固定大小的对象。如果我使用 Eigen::VectorXdstd::vector<SSCCE_struct>然后内存使用量跳到 918MB。当我然后去 std::vector<SSCCE_struct*>它进一步跃升至 1185MB。

这些测量将高度依赖于编译器。我使用 VS2013 编译 32 位代码。

关于c++ - 动态 vector 的特征库内存使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22932260/

相关文章:

c++ - 处理返回 std::string 的函数中的异常

c++ - vector constructor 创建少一个元素的 vector

c++ - RAS API。 sizeof(RASDIALPARAMS) 是错误的。错误 632

c++ - 模拟窗口的移动并让它对碰撞使用react

php - 跟踪方法的内存使用情况

c - 运行内存中存储的代码

c++ - 在 C++ 字符串中转义 XML/HTML 的最有效方法?

c++ - 为什么 g++ 不能编译一个简单的 GTK 程序?

.net - WM_SETREDRAW 并丢失 z 顺序/焦点

python - 迭代器在 Python 中节省内存吗?