0

In my program I have the following typedef:

typedef shared_ptr<IFrameObserver> IFrameObserverPtr;

And, later, this line of code:

IFrameObserverPtr myObv(new MyObserver(cameras[0]))

. . . in which MyObserver is created in the constructor of IFrameObserverPtr. The problem is that the MyObserver class creates a 6mB bitmap each time it gets created, and since it's never getting deleted, this causes a pretty severe memory leak (this line gets called 10 times a second).

My question is short and simple: How do I explicitly delete the new MyObserver to save myself from this memory leak?

For a reference as to how utterly horrible my memory leak is, here is my task manager during a partial execution of my program:

horrible memory leak


EDIT: Okay I've spent the last 2 hours trying to fix this to no avail. Doing . . .

myObv.reset();

. . . didn't work.

Just so everyone can see what's going on inside the MyObserver class, here it is:

class MyObserver : public IFrameObserver
{
public:

    HBITMAP hbm;

    BITMAPINFOHEADER* bi;

    MyObserver(CameraPtr pCamera) : IFrameObserver(pCamera) {};
    ~MyObserver(){delete hbm;}

    HBITMAP GetBMP()
    {
        return hbm;
    }

    void FrameReceived ( const FramePtr pFrame )  
    {
        DbgMsg(L"Frame Received\n");


        //////////////////////////////////////////////////////////////////////////
        //////////  Set Bitmap Settings   ////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////////

        //fileheader
        BITMAPFILEHEADER* bf = new BITMAPFILEHEADER;
        bf->bfType = 0x4d42;
        bf->bfSize = 6054400 + 54;
        bf->bfOffBits = 54;

        //infoheader
        bi = new BITMAPINFOHEADER;
        bi->biSize = 40;
        bi->biWidth = 2752;
        bi->biHeight = -733;
        bi->biPlanes = 1;
        bi->biBitCount = 24;
        bi->biCompression = 0;
        bi->biSizeImage = 6054400;
        bi->biXPelsPerMeter = 2835;
        bi->biYPelsPerMeter = 2835;
        bi->biClrUsed = 0;
        bi->biClrImportant = 0;

        //image data in VmbPixelFormatMono8
        VmbUchar_t* imageData;
        pFrame->GetImage(imageData);


        //////////////////////////////////////////////////////////////////////////
        //////////  Output File to .bmp   ////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////////

        BITMAPINFO* bmi;
        bmi = (BITMAPINFO*)bi;

        HDC hdc = ::GetDC(NULL);

        hbm = CreateDIBitmap(hdc, bi, CBM_INIT, imageData, bmi, DIB_RGB_COLORS);

        delete  bf;
        delete  bi;
        //free(imageData); //doesn't work, crashes
        //delete imageData; //doesn't work, crashes
        imageData = NULL;   //doesn't crash, but I don't think this frees the memory
        DeleteObject(hdc);  



    }
};

I've tried everything I can think of to free the 5.77 mB this objects makes when it's created, and I cannot figure out how to do it.

xcdemon05
  • 1,372
  • 5
  • 25
  • 49

3 Answers3

2

Assuming typedef shared_ptr<IFrameObserver> IFrameObserverPtr as you say in your comment, then it will decrement the reference count when it goes out of scope.

So there are several possibilities:

  1. The shared_ptr you are using is broken. This is highly unlikely if it's a boost:: or std:: shared_ptr.
  2. You are passing the shared_ptr into another function or object and it creates another shared_ptr to the same object, preventing its destruction. In this case, find where the unwanted object retention is taking place.
  3. The destructor for MyObserver destruction does not free the bitmap.
  4. The destructor for IFrameObserver is not virtual and so is not calling the MyObserver destruction which frees the bitmap.

So the first test is to determine whether this:

{
    IFrameObserverPtr myObv(new MyObserver(cameras[0]));
}

calls the MyObserver destructor. If not, then 4 or 3 will apply.

If that block leaks the bitmap, then ~MyObserver is faulty.

If that block frees the bitmap, then look into what else is retaining the object.


With your edit showing the destructor and the code which creates the bitmap for which hbm is the handle, it's obvious that the destructor does not destroy the bitmap.

Since you create hbm with CreateDIBitmap, a Win32 API call, you need to release it with the corresponding Win32 API call, which msdn.microsoft.com/en-gb/library/windows/desktop/… says is DeleteObject, rather than just using C++ delete on the handle to the bitmap - you're trying deleting the handle (which is a void* pointer so is undefined behaviour). You're not telling Windows to free the resource the handle points to.

You possibly are also leaking the image data, since there are commented out attempts to free it - check the documentation Frame::GetImage (or whatever call underlies its implementation if it's your own code) as to whether you have to call anything to free that, or whether it remains owned by the frame.

Community
  • 1
  • 1
Pete Kirkham
  • 48,893
  • 5
  • 92
  • 171
  • 1) It's std::shared_ptr, 2)I've checked everywhere and found nothing. I've used both Visual Leak Detector and CrtDbg to search for memory leaks, both of which point to that line of code. 3)It does 4) It's virtual – xcdemon05 Feb 08 '13 at 16:35
  • @xcdemon05 do you get the leak with the three lines of code I posted? If not, it's most likely 2. If you do, then step into the shared_ptr destructor and debug it. – Pete Kirkham Feb 08 '13 at 16:36
  • Can you clarify what you mean by "determine whether `IFrameObserverPtr myObv(new MyObserver(cameras[0]));` calls the MyObserver destructor"? Why would that line of code call the destructor? – xcdemon05 Feb 08 '13 at 17:14
  • @xcdemon05 I said "three lines of code". When myObv goes out of scope, the shared_ptr destructor will decrement the shared reference count. As it is the only shared_ptr referencing the object in that code, the reference count will reach zero and IFrameobserver's destructor should be called. – Pete Kirkham Feb 08 '13 at 18:58
  • Ah i gotcha. When it goes out of scope my debugger stepped into the destructor so that is getting called for sure, but when it tried to execute `delete hbm;` inside the destructor there was an access violation error. – xcdemon05 Feb 08 '13 at 19:17
0

If the IFrameObserver implementation is meant to own the MyObserver you're passing to its constructor, get its destructor to delete it and then make sure IFrameObserver gets destroyed promptly. If someone else is supposed to own the MyObserver make sure they have a pointer and know when to delete it.

If you don't know who's supposed to own it, you need to figure it out. The only way to get your memory management right in C++ is to understand object ownership and lifecycles. Once you get that sorted out, things like shared_ptr and unique_ptr should allow you to implement it quite easily.

Matthew Walton
  • 9,809
  • 3
  • 27
  • 36
0

an IFrameObserverPtr has the definition typedef shared_ptr<T>(IFrameObserver) IFrameObserverPtr

The problem is that the MyObserver class creates a 6mB bitmap each time it gets created

it's never getting deleted

I assume you meant typedef shared_ptr<IFrameObserver> IFrameObserverPtr and your computer has a broken copy/paste mechanic.

Then either:

  1. the MyObserver destructor is broken and must be fixed, or
  2. the MyObserver destructor and its base equivalent the IFrameObserver destructor were not marked virtual.

The MyObserver object itself will already be destroyed when the last remaining IFrameObserverPtr to it goes out of scope, so when that destruction process is fixed to remove the leak, you'll be fine.

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055