.net C+中的内存泄漏+/CLI方法

.net C+中的内存泄漏+/CLI方法,.net,c++-cli,com-interop,.net,C++ Cli,Com Interop,我在我的代码中找到了此调用的内存泄漏: BitmapSource snapshot = VideoPlayer.GetCurrentImage(); VideoPlayer是一个C++/CLI库,此方法的代码为: WriteableBitmap^ VideoPlayback::GetCurrentImage() { BITMAPINFOHEADER bih; BYTE *pDib = 0; DWORD cbDib = 0; LONGLONG timeStamp

我在我的代码中找到了此调用的内存泄漏:

BitmapSource snapshot = VideoPlayer.GetCurrentImage();
VideoPlayer是一个C++/CLI库,此方法的代码为:

WriteableBitmap^ VideoPlayback::GetCurrentImage()
{
    BITMAPINFOHEADER bih;
    BYTE *pDib = 0;
    DWORD cbDib = 0;
    LONGLONG timeStamp = 0;

    memset(&bih, 0, sizeof(bih));
    bih.biSize = sizeof(BITMAPINFOHEADER);
    HRESULT hr = m_pPlayer->GetCurrentImage(&bih, &pDib, &cbDib, &timeStamp);

    if (FAILED(hr)) throw gcnew MFException(hr);

    WriteableBitmap^ res = ToWritableBitmap(bih, pDib, cbDib, true);

    CoTaskMemFree(pDib);

    return res;
}
和可写入位图:

WriteableBitmap^ VideoPlayback::ToWritableBitmap(const BITMAPINFOHEADER& bih, BYTE* pDib, DWORD cbDib, bool bInvert)
{
    WriteableBitmap^ res;
    AtlTrace(_T("image size: %d x %d, bitCount: %d, bufferSize: %d\n"), bih.biWidth, bih.biHeight, bih.biBitCount, cbDib);

    switch (bih.biBitCount)
    {
        //could there be any other format!?
    case 24:
        //AtlTrace(_T("24bit image not supported!"));
        res = gcnew WriteableBitmap(bih.biWidth, bih.biHeight, 72.0, 72.0, System::Windows::Media::PixelFormats::Bgr24, nullptr);
        break;
    case 32:
        res = gcnew WriteableBitmap(bih.biWidth, bih.biHeight, 72.0, 72.0, System::Windows::Media::PixelFormats::Bgr32, nullptr);
        break;
    }
    if (res!=nullptr)
    {
        int stride = res->BackBufferStride;
        res->Lock();

        if (bInvert)
        {
            BYTE* pBuf = (BYTE*)res->BackBuffer.ToPointer();

            BYTE* pDest = pBuf + (bih.biHeight - 1) * stride;
            BYTE* pSrc = pDib;
            //the image is inverted
            for (int y = 0; y < bih.biHeight; y++)
            {
                memcpy(pDest, pSrc, stride);
                pSrc+=stride;
                pDest-=stride;
            }
        }
        else
        {
            BYTE* pDest = (BYTE*)res->BackBuffer.ToPointer();
            memcpy(pDest, pDib, bih.biSizeImage);
        }

        res->AddDirtyRect(System::Windows::Int32Rect(0, 0, bih.biWidth, bih.biHeight));
        res->Unlock();
    }   
    return res;
}
WriteableBitmap^VideoPlayback::ToWritableBitmap(常量BitMapInfo头和bih,字节*pDib,DWORD cbDib,布尔bInvert)
{
可写位图^res;
AtlTrace(_T(“图像大小:%d x%d,比特数:%d,缓冲区大小:%d\n”)、bih.biWidth、bih.biHeight、bih.bibibittcount、cbDib);
开关(bih.BIBIT计数)
{
//还有其他格式吗!?
案例24:
//AtlTrace(_T(“不支持24位图像”);
res=gcnew WriteableBitmap(bih.biWidth、bih.biHeight、72.0、72.0、System::Windows::Media::PixelFormats::Bgr24、nullptr);
打破
案例32:
res=gcnew WriteableBitmap(bih.biWidth、bih.biHeight、72.0、72.0、System::Windows::Media::PixelFormats::Bgr32、nullptr);
打破
}
如果(res!=nullptr)
{
int stride=res->BackBufferStride;
res->Lock();
if(bInvert)
{
字节*pBuf=(字节*)res->BackBuffer.ToPointer();
字节*pDest=pBuf+(bih.biHeight-1)*步幅;
字节*pSrc=pDib;
//图像是倒置的
对于(int y=0;yBackBuffer.ToPointer();
memcpy(pDest、pDib、波黑比西泽马吉);
}
res->AddDirtyRect(系统::Windows::Int32Rect(0,0,bih.biWidth,bih.biHeight));
res->Unlock();
}   
返回res;
}
多次调用此方法会导致某些对象被“固定”,并在运行
时导致高死区线程数!windbg中的线程
。正在运行
!gcroot
在这些死线程上我得到:

域(000000000 36553A0):句柄(固定):5417c8:根: 00000000 22423378(System.Object[])->
00000000 125F0C08(System.Collections.ArrayList)->
00000000 12D96950(System.Object[])->
00000000 12E44460(System.Windows.Media.MediaContext)->
00000000 12E43E80(System.Windows.Threading.Dispatcher)->
00000000 12E30480(System.Threading.Thread)

其中
System.Object[]
的地址始终相同


在这个调用之后,我如何正确地清理线程才能完成?还是C++代码有问题?

问题是我在后台线程中创建了BITMAP源。有一次我使用Dispatcher.Invoke调用了这个方法,线程泄漏消失了。

CLR使用固定对象数组来存储静态。我会在源代码中查找静态ArrayList。我认为您需要附加更多代码。我猜将是
到可写入位图
函数。它不会复制数据吗?你是说你有很多线程,但是你发布的代码中有线程。也许这是你应该研究的问题?@svick:我每次调用这个时都会创建一个新线程code@Krizz:添加了ToWritableBitmap函数。这是否意味着问题的根源是C++代码而不是C语言调用/清理?在C++/CLI调用返回指针以外的任何东西(我使用FreeCoTaskMem)之后,是否不需要释放内存?