none
Finding source of pinned objects and DeadThreads?

    Soru

  • I'm trying to find out why my app is leaking the thread stack. In Windbg my !threads output shows a high DeadThread count. If I run !gcroot on these dead threads I get lots of:

    DOMAIN(00000000036553A0):HANDLE(Pinned):5417c8:Root:  0000000022423378(System.Object[])->
      00000000125f0c08(System.Collections.ArrayList)->
      0000000012d96950(System.Object[])->
      0000000012e44460(System.Windows.Media.MediaContext)->
      0000000012e43e80(System.Windows.Threading.Dispatcher)->
      0000000012e30480(System.Threading.Thread)

    The address of the System.Object[] is always the same.

    I'm a bit out of my depth here and don't know how to debug this. Can someone tell me where to go from here and find the source of the object and why it's pinned?

    Thanks in advance!

    03 Mart 2012 Cumartesi 07:02

Yanıtlar

Tüm Yanıtlar

  • It looks like the arrayList is pinned and never freed. Since, arrayList is pinned it is considered to be a root and never garbage collected. So, check all objects of type GCHandle and check whether they are still allocated (You can use IsAllocated) property. If yes, then make sure to call Free() on those objects so that they are not considered to be in use.

    I hope this helps.


    Please mark this post as answer if it solved your problem. Happy Programming!

    03 Mart 2012 Cumartesi 13:48
  • Hi Adavesh,

    It looks to me like this is something to do with the UI that I don't explicitly program (System.Windows.Media.MediaContext). So I don't know where I would place the GCHandle code you refer to. Plus I would rather find out why it is being pinned and try to resolve it through cleaner code than code against the Garbage Collection.

    Is there any way to find out what is pinning the object and what part in my code it relates to?

    03 Mart 2012 Cumartesi 23:20
  • Is there any way to find out what is pinning the object and what part in my code it relates to?

    You can use CLRProfiler to know what objects are pinned.

    I would rather find out why it is being pinned and try to resolve it through cleaner code than code against the Garbage Collection.

    I think the pinning is necessary because the managed array is passed to unmanaged code. During garbage collection, if the address of the array or any of the array elements change, then unmanaged code might be referring to invalid address. Hence, to ensure address remains intact during GC, the array needs to be pinned (if not you, I think it is automatically done).

    So, if you say you are not explicitly pinning the array, then CLR might be doing that for you. If CLR is doing that for you, then it should automatically unpin the array when you dispose the unmanaged object that refers to the array and I think you have some media player objects not disposed properly.

    So, Check whether you are calling Dispose on all media objects. If Dispose is not available, then call Marshal.FinalReleaseComObject or other methods to explicitly release the Com objects.

    I hope this helps.


    Please mark this post as answer if it solved your problem. Happy Programming!

    04 Mart 2012 Pazar 05:46
  • Thank you Adavesh, that helped a lot. I've tracked the problem down to a call to a C++/CLI component:

    BitmapSource snapshot = VideoPlayer.GetCurrentImage();

    The C++/CLI code is:

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

    Do you know how to release that memory? I couldn't find any reference on this or in the Marshal class.

    06 Mart 2012 Salı 11:30
  • I am not familiar with C++. Please correct me if I am getting it wrong.

    One problem I see in GetCurrentImage function is, if m_pPlayer->GetCurrentImage failes, then it throws an exception and hence the memory of 'pDib' is never freed and it will leak memory. Apart from this, I don't see any other problem in this function.

    The only other thing is, are you properly freeing WriteableBitmap object (retruned from GetCurrentImage method)?


    Please mark this post as answer if it solved your problem. Happy Programming!

    06 Mart 2012 Salı 17:30
  • The only other thing is, are you properly freeing WriteableBitmap object (retruned from GetCurrentImage method)?
    No I'm not, and I'm not sure how to do that which is the problem I think. Thanks!
    06 Mart 2012 Salı 19:49
  • I found the problem was creating the BitmapSource on a background thread. As soon as I used DispatcherInvoke to call the same method the thread leak went away.

    07 Mart 2012 Çarşamba 07:05
  • That's great to hear. Well done :)

    Please mark this post as answer if it solved your problem. Happy Programming!

    07 Mart 2012 Çarşamba 08:07