Я обнаружил утечку памяти для этого вызова в моем коде:
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;
}
и ToWriteableBitmap:
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;
}
Вызов этого метода несколько раз приводит к "закреплению" некоторого объекта и большому количеству DeadThread, когда я запускаю !threads
в windbg. Запустив !gcroot
на этих мертвых нитях, я получаю:
DOMAIN (00000000036553A0): HANDLE (Закреплено): 5417c8: Корень:
0000000022423378 (System.Object []) ->
00000000125f0c08 (System.Collections.ArrayList) ->
0000000012d96950 (System.Object []) ->
0000000012e44460 (System.Windows.Media.MediaContext) ->
0000000012e43e80 (System.Windows.Threading.Dispatcher) ->
0000000012e30480 (System.Threading.Thread)
Где адрес System.Object[]
всегда один и тот же.
Как правильно очистить после этого вызова, чтобы поток мог закончиться? Или это проблема с кодом C ++?