0

在我的程序中,我有以下 typedef:

typedef shared_ptr<IFrameObserver> IFrameObserverPtr;

然后,这行代码:

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

. . . 其中 MyObserver 是在 IFrameObserverPtr 的构造函数中创建的。问题是 MyObserver 类每次创建时都会创建一个 6mB 的位图,并且由于它永远不会被删除,这会导致非常严重的内存泄漏(该行每秒调用 10 次)。

我的问题很简短:如何显式删除新的 MyObserver 以使自己免受内存泄漏的影响?

有关我的内存泄漏有多可怕的参考,这是我的程序部分执行期间的任务管理器:

可怕的内存泄漏


编辑:好的,我花了过去 2 个小时试图解决这个问题,但无济于事。正在做 。. .

myObv.reset();

. . . 没用。

这样每个人都可以看到 MyObserver 类中发生了什么,这里是:

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);  



    }
};

我已经尝试了所有我能想到的方法来释放这个对象在创建时产生的 5.77 mB,但我不知道该怎么做。

4

3 回答 3

2

假设typedef shared_ptr<IFrameObserver> IFrameObserverPtr正如您在评论中所说,那么当它超出范围时它将减少引用计数。

所以有几种可能:

  1. 您正在使用的 shared_ptr 已损坏。如果它是 boost:: 或 std::shared_ptr,这是极不可能的。
  2. 您将 shared_ptr 传递给另一个函数或对象,它会为同一个对象创建另一个 shared_ptr ,从而防止其破坏。在这种情况下,找到不需要的对象保留发生的位置。
  3. MyObserver 销毁的析构函数不会释放位图。
  4. IFrameObserver 的析构函数不是虚拟的,因此不会调用释放位图的 MyObserver 析构函数。

所以第一个测试是确定是否:

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

调用 MyObserver 析构函数。如果没有,那么 4 或 3 将适用。

如果该块泄漏位图,则 ~MyObserver 有问题。

如果该块释放位图,则查看还有什么保留了该对象。


随着您的编辑显示析构函数和创建作为hbm句柄的位图的代码,很明显析构函数不会破坏位图。

由于您使用CreateDIBitmapWin32 API 调用创建 hbm,因此您需要使用相应的 Win32 API 调用(msdn.microsoft.com/en-gb/library/windows/desktop/... 说是)来释放它DeleteObject,而不仅仅是使用 C++ 删除在位图的句柄上-您正在尝试删除句柄(这是一个void*指针,因此是未定义的行为)。您不是在告诉 Windows 释放句柄指向的资源。

您可能还泄漏了图像数据,因为有注释掉试图释放它 - 检查文档Frame::GetImage(或任何调用它的实现,如果它是您自己的代码)关于您是否必须调用任何东西来释放它,或者它是否仍然归框架所有。

于 2013-02-08T13:53:37.137 回答
0

如果IFrameObserver实现是为了拥有MyObserver你传递给它的构造函数,让它的析构函数删除它,然后确保IFrameObserver被立即销毁。如果其他人应该拥有它,请MyObserver确保他们有一个指针并知道何时删除它。

如果你不知道谁应该拥有它,你需要弄清楚。在 C++ 中正确进行内存管理的唯一方法是了解对象所有权和生命周期。一旦你把它整理好,就像shared_ptr并且unique_ptr应该允许你很容易地实现它。

于 2013-02-08T13:38:51.430 回答
0

IFrameObserverPtr定义typedef shared_ptr<T>(IFrameObserver) IFrameObserverPtr

问题是MyObserver该类每次创建时都会创建一个 6mB 的位图

它永远不会被删除

我假设您的意思是typedef shared_ptr<IFrameObserver> IFrameObserverPtr并且您的计算机的复制/粘贴机制损坏。

然后:

  1. 析构函数坏了MyObserver,必须修复,或者
  2. 未标记析MyObserver构函数及其等效的析构函数。IFrameObservervirtual

MyObserver最后一个对象IFrameObserverPtr超出范围时,对象本身已经被销毁,所以当销毁过程被修复以消除泄漏时,你会没事的。

于 2013-02-08T13:55:15.317 回答