【问题标题】:Odd memory leak with pointer arrays when multithreading that do not occur while single threading单线程时不会发生多线程时指针数组的奇数内存泄漏
【发布时间】:2015-02-10 17:35:38
【问题描述】:

经过一整天的调试,我注意到调用以下函数时总是会发生内存泄漏:

void merge(TContainer<T> List2)
{

    TContainer<T> temp(this->Size);

    for (int i = 0; i < this->Size; i++)
    {
        temp.Interface[i] = this->Interface[i];
    }

    this->Interface = new T[Size + List2.size()];
    Size = Size + List2.size();


    for(int i = 0; i < List2.size(); i++)
    {
        Interface[i] = List2[i];
    }

    for(int i = List2.size(); i < Size; i++)
    {
        Interface[i] = temp[i];
    };
    delete[] temp.Interface;
}

代码内:

    TContainer_Short<unsigned short> Temp = TContainer_Short<unsigned short>(0);
    for(int i = (ToUpdate.size() - 1); i >= 0; i--)
    {
        UpdateInUse = true;
        ToUpdate[i].Ad.push_back(AdQueue[i].Indirect[0].Address);
        auto Entity = ToUpdate[i];
        UpdateInUse = false;
        float HighestScore = 0;
        int Index = 0;
        //Go through all the advertisements on their queue
        //Make sure our last index is always the next plot point in our story.

        for(int j = 0; j < ToUpdate[i].Ad.size(); j++)
        {
            AdvertisementBase Ad = *World::get()->getTemplateAd(Entity.Ad[j]);

            float temp = returnScore(Entity.Index, Ad);
            //If its higher than our current score, set i to this index
            if(temp > HighestScore)
                Index = j;
        }
        //Index is last pos when we're currently continuing our plot queue. We haven't changed our mind about what advertisement we want

        if(Index !=(Entity.Ad.size() - 1))
        {

            AdvertisementBase *Ad = World::get()->getTemplateAd(Entity.Ad[Index]);
            this->reduceAdChain(Entity.Index, Ad);

        }

        else
        {
            //Makes sure that the entity is on track for the next goal that it had already determined
           plan(Entity.Index,AdQueue.Interface[Entity.Index].Indirect[0].Address);
        }
        Temp.push_back(Entity.Index);
        ToUpdate.pop_back();

    }
    if(!ExecutingInUse)
    {
        ExecutingInUse = true;
        Executing.merge(Temp);
        ExecutingInUse = false;
    }
    delete[] Temp.Interface;
}

但是,我似乎无法弄清楚为什么它只在有多个线程时才会发生。数组本身一次只能被一个线程(原子)引用,所以它不应该成为问题。

删除 Executing::merge 引用可以消除内存泄漏,并且在单线程场景中肯定会显着提高性能。

更奇怪的是,merge还用在了其他地方:

void reduceAdChain(unsigned short Index, TContainer<AdvertisementReference> Ads)
{
    AdQueue[Index].Indirect.merge(Ads);
}

即使调用reduceAdChain 的频率几乎比Executing::merge 高出一个数量级,也不会产生内存泄漏。并且删除该区域中的合并,不会产生明显的性能提升,即使

A) reduceAdChain 用于合并的数组的平均大小几乎是传入 Executing::merge 的数组的 3 倍

B) reduceAdChain 的总长度几乎是 Executing 长度的 5 倍。

但是,执行在每次迭代结束时都会被清除。

这是我在多线程环境中遇到的最奇怪的事情之一。

执行被使用的地方:

        if(!m_simulated_entities[i]->ExecutingInUse)
        {
            for (int j = 0; j < m_simulated_entities[i]->Executing.size(); )
            {
                // Retrieve Tag Data and Update Constants
                m_simulated_entities[i]->ExecutingInUse = true;
                ExecutingIndex = m_simulated_entities[i]->Executing[j];
                m_simulated_entities[i]->ExecutingInUse = false;


                TagIndex = m_simulated_entities[i]->TagIndicesPerEntity[ExecutingIndex];
                now = std::chrono::system_clock::now();
                time_now = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();

                if (m_simulated_entities[i]->Timing[m_simulated_entities[i]->Executing[j]].TimeConstant == 0)
                {
                    //Make sure all of our new attribute values still allow this entity to live
                    if(!m_simulated_entities[i]->updateTick(ExecutingIndex))
                        m_simulated_entities[i]->removeInstance(ExecutingIndex);
                    else
                    {
                        //Compute our new transfer constant
                        m_simulated_entities[i]->prepare(ExecutingIndex);
                        //Update the tagging system
                        m_simulated_entities[i]->updateTags(ExecutingIndex);
                        //Search for new decisions
                        m_simulated_entities[i]->ToSearch.push_back(ExecutingIndex);
                    }
                    //Remove the index from execution
                    m_simulated_entities[i]->ExecutingInUse = true;
                    m_simulated_entities[i]->Executing.Remove(j);
                    m_simulated_entities[i]->ExecutingInUse = false;
                }

                else if (time_now - m_simulated_entities[i]->Timing[ExecutingIndex].LastUpdateTime > updateConstants[TagIndex])
                {
                    m_simulated_entities[i]->Timing[ExecutingIndex].TimeConstant--;
                    m_simulated_entities[i]->Timing[ExecutingIndex].LastUpdateTime = time_now;
                    j++;
                }
            }
        }

对于测试,updateTick 被禁用并且将始终返回 true,因为允许该函数正确执行会使查找内存泄漏变得更加困难。

【问题讨论】:

  • 什么是执行实例?它是如何声明的?
  • Executing 是当前正在执行他们通过模糊逻辑控制器做出的决策的所有实体的列表。我将编辑帖子以显示其用例。
  • 查看你的merge(),你为分配给this->Interface的新接口分配内存。旧记忆会怎样?这可能需要释放。

标签: c++ arrays multithreading memory-leaks


【解决方案1】:

在函数合并中:

 this->Interface = new T[Size + List2.size()];

你应该检查指针this-&gt;Interface是否是NULL,如果不是,应该先释放它。否则如果多次调用merge函数,就会泄漏。

所以代码是:

if (this->Interface != NULL)
   delete[]  this->Interface;
this->Interface = new T[Size + List2.size()];

【讨论】:

  • 耶!这似乎可以解决内存泄漏问题。谢谢!
  • 还不能。必须等待 3 分钟
  • 奇怪的是,只使用单线程时没有内存泄漏。这虽然很有效
  • @LouisCastricato 在函数merge中添加日志,在分配新内存之前记录this->Interface的值,你会发现的。
【解决方案2】:

对不起,可能是愚蠢的问题:如果您有向量作为“ToUpdate[i].Ad”等,为什么不使用“this->Interface”作为向量呢?这可以为您节省大量寻找此漏洞的时间。

【讨论】:

  • 仅仅因为它更易于阅读,并且在任何地方都使用 this->接口使得当您将所有内容移动到缓存简洁架构时更难理解
猜你喜欢
  • 1970-01-01
  • 2014-10-29
  • 2013-12-18
  • 2015-08-14
  • 1970-01-01
  • 1970-01-01
  • 2021-11-26
  • 2012-10-11
  • 2017-02-04
相关资源
最近更新 更多