开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜