4

我有一个简单的同步队列

 template <typename T>

    class SynchronisedQueue
    {
    public:

        void Enqueue(const T& data)
        {
            boost::unique_lock<boost::mutex> lock(queueMutex);
            dataQueue.push(data);
            conditionVariable.notify_one();
        } 

        T Dequeue()
        {
            boost::unique_lock<boost::mutex> lock(queueMutex);

            while (dataQueue.size()==0) 
            {
                conditionVariable.wait(lock);
            }

            T result=dataQueue.front(); dataQueue.pop();
            return result;
        } 


    private:

    std::queue<T> dataQueue;                        // Use STL queue to store data
boost::mutex queueMutex;                        // The mutex to synchronise on
boost::condition_variable conditionVariable;    // The condition to wait for
};

当我从队列中出列时,有时会损坏堆......

HEAP: Free Heap block ccb1080 在 ccb13c0 被释放后修改

调用堆栈是:

ntdll.dll!76fa5654()    
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] 
ntdll.dll!76f6a554()    
ntdll.dll!76f35a70()    
ntdll.dll!76fa5eff()    
ntdll.dll!76f6a3ba()    
ntdll.dll!76f35a70()    
msvcr90d.dll!_heap_alloc_base(unsigned int size=1222)  Line 105 + 0x28 bytes    C
msvcr90d.dll!_heap_alloc_dbg_impl(unsigned int nSize=1186, int nBlockUse=1, const char * szFileName=0x00000000, int nLine=0, int * errno_tmp=0x1310ee18)  Line 427 + 0x9 bytes  C++
msvcr90d.dll!_nh_malloc_dbg_impl(unsigned int nSize=1186, int nhFlag=0, int nBlockUse=1, const char * szFileName=0x00000000, int nLine=0, int * errno_tmp=0x1310ee18)  Line 239 + 0x19 bytes    C++
msvcr90d.dll!_nh_malloc_dbg(unsigned int nSize=1186, int nhFlag=0, int nBlockUse=1, const char * szFileName=0x00000000, int nLine=0)  Line 296 + 0x1d bytes C++
msvcr90d.dll!malloc(unsigned int nSize=1186)  Line 56 + 0x15 bytes  C++
msvcr90d.dll!operator new(unsigned int size=1186)  Line 59 + 0x9 bytes  C++
x.ax!std::_Allocate<unsigned char>(unsigned int _Count=1186, unsigned char * __formal=0x00000000)  Line 43 + 0x9 bytes  C++
ax.ax!std::allocator<unsigned char>::allocate(unsigned int _Count=1186)  Line 145 + 0xb bytes   C++
ax.ax!std::vector<unsigned char,std::allocator<unsigned char> >::_Buy(unsigned int _Capacity=1186)  Line 1110 + 0xf bytes   C++
ax.ax!std::vector<unsigned char,std::allocator<unsigned char> >::vector<unsigned char,std::allocator<unsigned char> >(const std::vector<unsigned char,std::allocator<unsigned char> > & _Right=[1186](83 'S',50 '2',54 '6',67 'C',162 '¢',4 '',0,0,108 'l',0,0,0,2 '',64 '@',0,0,6 '',14 '',64 '@',0,35 '#',2 '',147 '“',76 'L',114 'r',53 '5',0,0,54 '6',79 'O',78 'N',4 '',0,0,0,0,54 '6',79 'O',78 'N',4 '',0,0,0,0,255 'ÿ',255 'ÿ',255 'ÿ',255 'ÿ',255 'ÿ',255 'ÿ',255 'ÿ',255 'ÿ',106 'j',4 '',0,0,0,0,0,1 '',65 'A',154 'š',3 '',1 '',176 '°',159 'Ÿ',255 'ÿ',240 'ğ',199 'Ç',...))  Line 501 + 0x11 bytes    C++
ax.ax!SynchronisedQueue<std::vector<unsigned char,std::allocator<unsigned char> > >::Dequeue()  Line 32 + 0xc bytes C++
ax.ax!PPin::FillBuffer(IMediaSample * pSample=0x0cadbea8)  Line 225 + 0x12 bytes    C++
ax.ax!PPin::DoBufferProcessingLoop()  Line 300 + 0x13 bytes C++
ax.ax!CSourceStream::ThreadProc()  + 0x13e bytes    
ax.ax!CAMThread::InitialThreadProc()  + 0x51 bytes  
kernel32.dll!753bed6c()     
ntdll.dll!76f4377b()    
ntdll.dll!76f4374e() 

什么可能导致此堆损坏?如何调试堆损坏错误?有任何想法吗...

更新: 使用示例

// Enqueue
void GetVideoStreams( BYTE *pData)
{
 std::vector<BYTE> vecFrame(pData, pData + nLen/sizeof(pData[0]));
 IncomingFramesQueue.Enqueue(vecFrame);

}

//Dequeue
void ConsumeVideoStreams()
{

 vector<BYTE> data = IncomingFramesQueue.Dequeue();

}
4

3 回答 3

2

如上所述 - 您的代码和您发布的堆栈跟踪表明一些内存分配正在进行中。连同错误消息,我假设堆损坏发生在其他地方,并且每次都在出队时弹出,因为它使用大量内存来复制这些向量。

使用一些内存分析工具的评估版(例如http://www.softwareverify.com/cpp-memory.php)来查找错误。市场上也有一些免费工具(最著名的是 Valgrind),但我不知道有什么免费的适用于 Visual C++ 的好工具。

此外,您可以查看这篇文章如何调试堆损坏错误?此处了解有关如何解决此错误的其他方法。

从我到目前为止看到的情况来看,错误不在您发布的代码中。如果您需要更多帮助,请提供一个包含错误的小型自包含示例。


我刚刚发现了一个可能值得一试的免费工具:Dr. Memory。我当然从stackoverflow获得了链接。

于 2012-08-15T13:05:58.497 回答
1

是的,。您可能正在混合运行时库的 Release 和 Debug 版本。

在 Windows(仅 AFAIK)上,有 2 个不同的运行时库,发布版本会按照您的预期进行内存分配,但调试版本会在所有分配周围添加保护块,以便它可以跟踪缓冲区溢出和其他内存错误。这个系统的问题是,如果你在同一个应用程序中混合一个 Release 和一个 Debug 库,你将在 Release 中分配(比如说)10 个字节,然后在 Debug 中释放 18 个字节(4+10+4)。

诀窍是每次都构建和链接所有 Debug 或所有 Release。或者,如果您必须在调试版本中使用 Release 库,那么您必须确保在 dll 中进行的所有分配也由同一个库释放 - 不允许使用 CRT 新/删除例程,将它们包装在功能。这确保了 dll A 中的 10 字节分配将被同一个 dll 释放,这显然只会删除 10 字节。

编辑:

好的,如果不是这样,那么在使用复制构造函数(Dequeue 的第 32 行)分配新向量时查看调用堆栈会显示错误,因此首先将该行拆分为 2 个语句,以便您可以查看它是否是副本,或者导致问题的pop(我总是倾向于在它们之间放置一个调试语句,以确保您知道哪一行是问题所在)。

您的示例代码显示了访问队列的 2 种不同方式 -> Enqueue 和 .Dequeue,这表明队列本身更加复杂。

于 2012-08-15T10:39:05.790 回答
0

这些是非常有用的函数,可以调用以验证堆在调试构建中没有损坏:

_ASSERTE(_CrtCheckMemory());

您还可以设置标志,以便在退出时检查内存泄漏:

通过设置(或)以下标志:_CRTDBG_LEAK_CHECK_DF

有关详细信息,请参阅以下页面:

http://msdn.microsoft.com/en-us/library/e73x0s4b(v=vs.110).aspx http://msdn.microsoft.com/en-us/library/5at7yxcs.aspx

于 2013-07-19T20:20:00.973 回答