我读了很多关于内存损坏的帖子,似乎这是一个相当难以解决的问题。当我在linux机器上运行代码时,它执行得很好,并且valgrind没有报告任何泄漏或错误。然而,当我用VS2008在我的实验室的windows机器上运行代码时,我得到了一个糟糕的分配错误,用_RAISE(nomem)停止。这对我来说似乎很奇怪,因为我本以为valgrind会抓住它。
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{ // try to allocate size bytes
void *p;
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{ // report no memory
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}
从我所读到的,似乎这个问题往往来自于写过去的内存分配块的结束或之后,它已被释放,但我没有任何运气确定可能发生的地方。这是我尝试运行发布版本后的调用堆栈。
KernelBase.dll!_RaiseException@16() + 0x58 bytes
msvcr90.dll!_CxxThrowException(void * pExceptionObject=0x0040f6d4, const _s__ThrowInfo * pThrowInfo=0x6f63d604) Line 161 C++
msvcr90.dll!operator new(unsigned int size=4) Line 63 + 0x17 bytes C++
tempMem.exe!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=[...]()) Line 500 + 0x31 bytes C++
tempMem.exe!DendriteSegment::DendriteSegment(const DendriteSegment & __that={...}) + 0x4a bytes C++
tempMem.exe!std::list<DendriteSegment,std::allocator<DendriteSegment> >::_Buynode(std::_List_nod<DendriteSegment,std::allocator<DendriteSegment> >::_Node * _Next=0x005d84d0, std::_List_nod<DendriteSegment,std::allocator<DendriteSegment> >::_Node * _Prev=0x0093af50, const DendriteSegment & _Val={...}) Line 1208 C++
tempMem.exe!TP::adaptSegments(Cell * & cellToAdapt=0x005d8450, std::list<segUpdate,std::allocator<segUpdate> > & segUpdateList=[1]({segToUpdate=0x00000000 synapseChanges=[0]() newSynapsesToAdd=[2](0x005bc8f8 {DSlist=[19]({sequenceSegment=true synapse=[3](0x005d79a0 {DSlist={...} connected=0x005d7af8 currentState=0x005d79c0 ...},0x005d7ef8 {DSlist={...} connected=0x005d8050 currentState=0x005d7f18 ...},0x005d8450 {DSlist={...} connected=0x005d85a8 currentState=0x005d8470 ...}) permanence=[3](80 'P',80 'P',80 'P') ...},. ), bool posReinforce=true) Line 701 + 0x1b bytes C++
tempMem.exe!Level::TPlearning() Line 236 + 0x26 bytes C++
tempMem.exe!main(int argc=, char * * argv=) Line 96 C++
msvcr90.dll!_encode_pointer(void * ptr=0x6f5d3607) Line 114 + 0x5 bytes C
0069ee20()
msvcr90.dll!_initterm(void (void)* * pfbegin=0x00000001, void (void)* * pfend=0x000a1ef8) Line 903 C
tempMem.exe!__tmainCRTStartup() Line 582 + 0x17 bytes C
kernel32.dll!@BaseThreadInitThunk@12() + 0x12 bytes
ntdll.dll!___RtlUserThreadStart@8() + 0x27 bytes
ntdll.dll!__RtlUserThreadStart@8() + 0x1b bytes
当运行一个调试会话,我得到一个不同的错误(它似乎不发生所有的时间虽然…)
return HeapAlloc(_crtheap, 0, size ? size : 1);
从这里#ifdef _WIN64
return HeapAlloc(_crtheap, 0, size ? size : 1);
#else /* _WIN64 */
if (__active_heap == __SYSTEM_HEAP) {
return HeapAlloc(_crtheap, 0, size ? size : 1);
} else
if ( __active_heap == __V6_HEAP ) {
if (pvReturn = V6_HeapAlloc(size)) {
return pvReturn;
}
}
在这种情况下,调用堆栈是
ntdll.dll!_RtlpBreakPointHeap@4() + 0x23 bytes
ntdll.dll!@RtlpAllocateHeap@24() + 0x57dbc bytes
ntdll.dll!_RtlAllocateHeap@12() + 0x502a bytes
ntdll.dll!_RtlDebugAllocateHeap@12() + 0xb5 bytes
ntdll.dll!@RtlpAllocateHeap@24() + 0x57c17 bytes
ntdll.dll!_RtlAllocateHeap@12() + 0x502a bytes
msvcr90d.dll!_heap_alloc_base(unsigned int size=38) Line 105 + 0x28 bytes C
msvcr90d.dll!_heap_alloc_dbg_impl(unsigned int nSize=2, int nBlockUse=1, const char * szFileName=0x00000000, int nLine=0, int * errno_tmp=0x0052f284) Line 427 + 0x9 bytes C++
msvcr90d.dll!_nh_malloc_dbg_impl(unsigned int nSize=2, int nhFlag=0, int nBlockUse=1, const char * szFileName=0x00000000, int nLine=0, int * errno_tmp=0x0052f284) Line 239 + 0x19 bytes C++
msvcr90d.dll!_nh_malloc_dbg(unsigned int nSize=2, int nhFlag=0, int nBlockUse=1, const char * szFileName=0x00000000, int nLine=0) Line 296 + 0x1d bytes C++
msvcr90d.dll!malloc(unsigned int nSize=2) Line 56 + 0x15 bytes C++
msvcr90d.dll!operator new(unsigned int size=2) Line 59 + 0x9 bytes C++
tempMem.exe!std::_Allocate(unsigned int _Count=2) Line 43 + 0xc bytes C++
tempMem.exe!std::allocator<uint8_t>::allocate(unsigned int _Count=2) Line 145 + 0x13 bytes C++
tempMem.exe!std::::_Buy(unsigned int _Capacity=2) Line 1115 + 0x14 bytes C++
tempMem.exe!std::::vector(const std::vector<uint8_t, std::allocator<uint8_t> > & _Right=[2](80 'P',80 'P')) Line 501 + 0x2b bytes C++
tempMem.exe!DendriteSegment::DendriteSegment() + 0x8b bytes C++
tempMem.exe!std::_Construct(DendriteSegment * _Ptr=0x007e7490, const DendriteSegment & _Val={...}) Line 52 + 0x97 bytes C++
tempMem.exe!std::allocator<DendriteSegment>::construct(DendriteSegment * _Ptr=0x007e7490, const DendriteSegment & _Val={...}) Line 155 + 0x15 bytes C++
tempMem.exe!std::::_Buynode(std::_List_nod<DendriteSegment, std::allocator<DendriteSegment> >::_Node * _Next=0x00637f60, std::_List_nod<DendriteSegment, std::allocator<DendriteSegment> >::_Node * _Prev=0x00bfcb50, const DendriteSegment & _Val={...}) Line 1199 + 0x47 bytes C++
tempMem.exe!std::::_Insert(std::list<DendriteSegment, std::allocator<DendriteSegment> >::_Const_iterator<1> _Where={sequenceSegment=true synapse=[0]() permanence=[0]() ...}, const DendriteSegment & _Val={...}) Line 718 + 0x65 bytes C++
tempMem.exe!std::::push_back(const DendriteSegment & _Val={...}) Line 670 + 0x6f bytes C++
tempMem.exe!TP::adaptSegments(Cell * & cellToAdapt=0x00637ee8, std::list<segUpdate, std::allocator<segUpdate> > & segUpdateList=[1](...), bool posReinforce=true) Line 701 + 0x16 bytes C++
tempMem.exe!TP::phase3() Line 949 + 0x3e bytes C++
tempMem.exe!Col::TPphase3() Line 398 + 0xd bytes C++
tempMem.exe!Level::TPlearning() Line 236 + 0x4a bytes C++
tempMem.exe!Network::runTPlearning() Line 93 + 0xd bytes C++
tempMem.exe!main(int argc=1, char * * argv=0x006f62a0) Line 93 + 0xd bytes C++
tempMem.exe!__tmainCRTStartup() Line 582 + 0x19 bytes C
tempMem.exe!mainCRTStartup() Line 399 C
kernel32.dll!@BaseThreadInitThunk@12() + 0x12 bytes
ntdll.dll!___RtlUserThreadStart@8() + 0x27 bytes
ntdll.dll!__RtlUserThreadStart@8() + 0x1b bytes
这是我第一次调试这种类型的问题,我希望我只是忽视/误解了一些明显的问题…
下面是adaptSegments函数的代码,它对应于调用堆栈中的这一行(Release)
tempMem.exe!TP::adaptSegments(Cell * & cellToAdapt=0x005d8450, std::list<segUpdate,std::allocator<segUpdate> > & segUpdateList=[1]({segToUpdate=0x00000000 synapseChanges=[0]() newSynapsesToAdd=[2](0x005bc8f8 {DSlist=[19]({sequenceSegment=true synapse=[3](0x005d79a0 {DSlist={...} connected=0x005d7af8 currentState=0x005d79c0 ...},0x005d7ef8 {DSlist={...} connected=0x005d8050 currentState=0x005d7f18 ...},0x005d8450 {DSlist={...} connected=0x005d85a8 currentState=0x005d8470 ...}) permanence=[3](80 'P',80 'P',80 'P') ...},. ), bool posReinforce=true) Line 701 + 0x1b bytes
bool TP::adaptSegments(Cell *& cellToAdapt,
std::list<segUpdate> & segUpdateList, bool posReinforce)
{
std::list<segUpdate>::iterator curSegUpdate;
std::list<activeSynapsePair>::iterator curSyn;
std::list<Cell *>::iterator synToAdd;
int size = 0;
//for each segUpdate element in the cell's segUpdateList
for (curSegUpdate = segUpdateList.begin();
curSegUpdate != segUpdateList.end(); ++curSegUpdate)
{
//if the segment already exists
if (curSegUpdate->segToUpdate != NULL)
{
//if sequence segment flag is true, set it on DS
if(curSegUpdate->sequenceSegment == true)
{curSegUpdate->segToUpdate->sequenceSegment = true;}
if (posReinforce == true)
{
//for each synapses permanence pair in segUpdate
for (curSyn = (curSegUpdate->
synapseChanges.begin());
curSyn !=(curSegUpdate->synapseChanges.end());
++curSyn)
{
//decrement inactive synapses
if (curSyn->second == false)
{
if (*(curSyn->first)-
permanenceDec < 0)
{*(curSyn->first) = 0;}
else
{*(curSyn->first)-=
permanenceDec;}
}
//increment active synapses
else if (curSyn->second == true)
{
if (*(curSyn->first)+
permanenceInc > 100)
{*(curSyn->first) =100;}
else
{*(curSyn->first)+=
permanenceInc;}
}
}
}
else if (posReinforce == false)
{
//for each synapses permanence pair in segUpdate
for (curSyn = (curSegUpdate->
synapseChanges.begin());
curSyn !=(curSegUpdate->synapseChanges.end());
++curSyn)
{
//decrement active synapses
if (curSyn->second == true)
{
if (*(curSyn->first)-
permanenceDec < 0)
{*(curSyn->first) = 0;}
else
{*(curSyn->first)-=
permanenceDec;}
}
}
}
//if adding synapses to an existing segment
if (curSegUpdate->newSynapsesToAdd.empty()==false)
{
if (curSegUpdate->segToUpdate->synapse.size()
<MAX_NUM_SYN)
{
//for each synapses in newSynapses
for (synToAdd =
curSegUpdate->newSynapsesToAdd.begin();
synToAdd != curSegUpdate->
newSynapsesToAdd.end(); ++synToAdd)
{
//add new synapse to list
curSegUpdate->segToUpdate->
synapse.push_back(*synToAdd);
//and permenance with initialPerm
curSegUpdate->segToUpdate->
permanence.push_back(initialPerm);
}
}//if less than MAX_NUM_SYN
}
}//end if segment already exists
//if segment doesn't exist, create a new segment & add synapses
else if (curSegUpdate->segToUpdate == NULL)
{
size = curSegUpdate->newSynapsesToAdd.size();
if (size != 0)
{
DendriteSegment myNewSeg; //create a new DS
//set sequenceSegment flag if it is true
if (curSegUpdate->sequenceSegment == true)
{myNewSeg.sequenceSegment = true;}
std::copy(curSegUpdate->newSynapsesToAdd.begin(),
curSegUpdate->newSynapsesToAdd.end(),
std::back_inserter(myNewSeg.synapse));
myNewSeg.permanence.resize(size, initialPerm);
//then add it to the cells list of DS
cellToAdapt->DSlist.push_back(myNewSeg);
}//if size not 0
}
}
return true;}
下一步是尝试应用程序验证程序。我尝试了Intel Inspector XE 2011,但它似乎没有检测到任何相关的内存问题。
Update:使用gflags,我发现问题的原因是std::vector中的元素指针。myVector.push_back(newElem)用于向vector中添加元素,导致指向vector中元素的指针变坏。我用std::list替换了向量,它没有同样的问题(见这里)
在Microsoft Debugging Tools for Windows (http://www.google.ca/search?sourceid=chrome&ie=UTF-8&q=debugging+tools+for+windows)工具包中尝试gflags。它允许您使用调试堆运行,该堆在问题发生时捕获问题,而不是在发生崩溃的站点很久之后出现的随机问题。