CRT & new - 30 calls of 92 bytes gives "bad_alloc nomem"
I'm writing a dynamic Octree for nearest neighbours of 2000+ objects in a C++ CRT DirectX Application. After 30 calls to the new operator the program throws "bad_alloc nomem". I am not using new anywhere else.
I'm now at a loss, following is an program outline and what I've done so far to the best of my ability to kill this bug. There's still a lot even after extensive snipping - but please don't let it put you off!
This is the class structure:
template <typename T, int MaxObjPerNode>
class Octree
{...
public:
struct Node
{
int objcnt; // 0 == Node 4bytes
Node* parent; // 0 == Base 4bytes
D3DXVECTOR3 centre; //12bytes
Node* children[8]; //32bytes
Cube bounderies; //24bytes (Struct of 6 floats)
T* obj[MaxObjPerNode]; //4bytes *4
Node()
{
objcnt=0;
parent = 0;
centre = D3DXVECTOR3(0,0,0);
for (int t=0; t<8; t++)
children[t] = 0;
for (int t=0; t<MaxObjPerNode; t++)
obj[t] = 0;
}
Node* GiveBirth(int const Oct)
{
//...Sanity checks & intalisation
Node* NewNode = 0;
//_CrtMemState myBug;
NewNode = new Node(); // Nasty man sits here
//_CrtMemCheckpoint(&myBug);
NewNode->parent = this;
NewNode->centre = NewCentre;
//... rest of NewNode init.
}
//... Other functions sniped
}
private:
Node* base;
int StrtVecOff;
public:
Octree(float InitalCubeSize, T* FirstObj, long VectorOffset)
{
//D3DXVECTOR3* pTemp;
base = new Node();
StrtVecOff = VectorOffset; //Used to find Current Position in class T
base->objcnt = 1;
base->parent = 0;
base->obj[0] = FirstObj;
//... rest of base init.
}
Node* Add(T* Obj)
{
D3DXVECTOR3* Point = (D3DXVECTOR3*)(((long)(Obj))+StrtVecOff);
Node* InNode;
InNode = FindPlaceInTree(Point);
// FindPlaceInTree returns as Parent if Leaf has not been created from Node - So create leaf child
if (InNode->objcnt == 0)
{
int Oct = InNode->FindOctet(Point);
Node* ChildNode = InNode->GiveBirth(Oct);
ChildNode->obj[ChildNode->objcnt] = Obj;
ChildNode->objcnt +=1;
return ChildNode;
}
//...Other situations snipped
}
};
This is the calling code,
Octree<Mob,4> MyTree((float)(1<<13), &Bird[0],((long)&Bird[0].Pos - (long)&Bird[0]) );
for (int t=0;t<BirdsCount;t++)
MyTree.Add(&Bird[t]);
The Octree initalises perfectly, base* is pointing correctly to valid data. All other calls (30 * 92 bytes) to new are fine until BANG. So I put in heap checks (at commented code in GiveBirth above); pass 1:
- myBug {pBlockHeader=0x003d3208 lCounts=0x0012f938 lSizes=0x0012f94c ...} _CrtMemState
+ pBlockHeader 0x003d3208
_CrtMemBlockHeader * //..snip - correct
- lCounts 0x0012f938 unsigned int [5]
[0] 0 unsigned int
[1] 2 unsigned int //First time past + base
[2] 45 unsigned int
[3] 0 unsigned int
[4] 0 unsigned int
- lSizes 0x0012f94c unsigned int [5]
[0] 0 unsigned int
[1] 184 unsigned int //Correct 2*92
[2] 8409 unsigned int
[3] 0 unsigned int
[4] 0 unsigned int
lHighWaterCount 12505 unsigned int
lTotalCount 18238 unsigned int
passes 2-28: are vitually all Idetical
pass 29:
- myBug {pBlockHeader=0x003d5c50 lCounts=0x0012f938 lSizes=0x0012f94c ...} _CrtMemState
+ pBlockHeader 0x003d5c50 {pBlockHeaderNext=0x003d5bb8 pBlockHeaderPrev=0x00000000 szFileName=0x00000000 <Bad Ptr> ...} _CrtMemBlockHeader *
- lCounts 0x0012f938 unsigned int [5]
[0] 0 unsigned int
[1] 30 unsigned int
[2] 45 unsigned int
[3] 0 unsigned int
[4] 0 unsigned int
- lSizes 0x0012f94c unsigned int [5]
[0] 0 unsigned int
[1] 2760 unsigned int
[2] 8409 unsigned int
开发者_StackOverflow中文版 [3] 0 unsigned int
[4] 0 unsigned int
lHighWaterCount 12505 unsigned int
lTotalCount 20814 unsigned int
There is no pass 30 :( I know I have more than 2760 bytes free (I'm not on a vic 20 any more!).
I've read many of the "related questions" and still no joy. Any suggestions welcome
mem exceptions are thrown when new
fails for any reason. It doesn't have to be an out of memory condition. Don't be fooled. Something is throwing an exception in the constructor.
There's a very good chance that with all that pointer manipulation, you did something out of order or just random and paved over some heap. That's another very possible scenario that would cause your memory allocation to fail.
Before you go too much further manually trying to pinpoint the problem, I'd suggest you try using page heap feature of gflags.exe (utility which is part of debugging tools for windows). All you have to do is open command line and type: "gflags /p /enable [your app.exe] /full". To return to normal, type: "gflags /p /disable [your app.exe]"
This tool is so easy to use and so helpful that as soon as I even suspect there might be a memory corruption, I run it first before attempting to find any other solution.
When page heap is enabled, lots of common memory errors that would've caused heap corruption will throw access violation exception as soon as they occur. This comes at the expense of using much more memory which is why you wouldn't want page heap to be enabled at all times.
This exception indicates an out-of-memory condition. You may have a memory leak - you haven't shown any of your destruction code, so I can't really tell if this is the case. You may also simply be using way too much memory.
It's also possible that heap corruption is occurring. I'm not sure what facilities Visual Studio has for tracking down heap corruption - you may want to try isolating an easily-ported example that reproduces the issue, and running it under valgrind on Linux.
精彩评论