【问题标题】:C++ bad allocation from heap fragmentation?C++ 来自堆碎片的错误分配?
【发布时间】:2014-01-23 19:37:48
【问题描述】:

我有以下问题。我循环运行了 3000 次。每次通过时,我都会在堆上分配一个字节缓冲区:

uint8_t* frameDest;
try { 
    frameDest= new uint8_t[numBytes * sizeof(uint8_t)];
    memcpy(frameDest, frameSource, _numBytes);
} catch(std::exception &e) {
    printf(e.what());
}

因此,分配的帧用作来自某些 frameSource._numBytes 的数据的目的地,它等于 921600。

接下来,在同一个循环中,frameDest 被推入 uint8_t* 指针(_frames_cache)的 std::vector。这个向量用作帧缓存并在每 X 帧被清理一次。使用当前设置,当超过 20 个时清理向量帧在缓存中。清理缓存的方法是这样的:

void  FreeCache()
{
    _frameCacheMutex.lock();
    try {
        int cacheSize = _frames_cache.size();
        for (int i = 0; i < cacheSize; ++i) {
            uint8_t* frm = _frames_cache.front();
            _frames_cache.erase(_frames_cache.begin());
            delete [] frm;
        }
    } catch (std::exception& e) {
        printf(e.what());
    }
    _frameCacheMutex.unlock();
}

问题:在第一个代码块中约 2000+ 帧之后引发了错误的分配异常。我用 Dr.Memory 测试了内存泄漏,但没有发现。此外,我在其他部分的分配/解除分配上没有收到错误或异常的程序。我有 2 个这样的代码实例在 2 个单独的线程中运行,这意味着在该程序的整个生命周期中,大约 6000 个分配/释放被处理,每个 960000 个字节。在整个应用程序中,有更多的堆分配,但是不是本部分中的频率。我已经读到现代编译器以非常先进的方式处理堆管理,但我仍然怀疑我的问题与内存碎片有关。我使用 Visual C++ 2012 编译器(C++ 11),32 位Windows7 64位操作系统下。

我的问题是:内存管理问题的可能性有多大,我应该编写还是使用自定义堆分配管理器?如果不是,会是什么?

【问题讨论】:

  • “目前超过...”你能改写一下吗?
  • 2000x~1M大约是2G。切换到 64 位。
  • frameDest= new uint8_t[numBytes * sizeof(uint8_t)]; 这是错误的:你永远不需要* sizeofnew。只需写frameDest = new uint8_t[numBytes];(当然,sizeof(uint8_t) 无论如何都应该是 1!)
  • 如果您在 2G/2G 分离的 32 位系统上保持在 2G 附近(Win32 AFAIK 的默认设置),您将始终面临随机分配失败的风险。如果你想保持 32 位,你需要非常非常小心地管理你的缓存(在启动时分配固定大小可能是最明智的做法)
  • @dyp Boost Pointer Container 值得一看

标签: c++ visual-c++ memory-management


【解决方案1】:

很难判断这是否是内存碎片问题。但是您可能需要考虑在开始时为帧分配固定数量的内存作为环形缓冲区,这样在运行时您就不会遇到任何碎片(也可以节省内存(取消)分配的时间)。当然,不确定这是否适用于您的用例。

【讨论】:

    猜你喜欢
    • 2018-02-12
    • 1970-01-01
    • 2018-01-17
    • 2011-07-25
    • 2014-07-14
    • 1970-01-01
    • 2012-04-03
    • 2012-04-28
    相关资源
    最近更新 更多