What are the challenges you face when working across database platforms? Take the survey
Options

Memory leak?

martinsmartins Posts: 2
edited March 27, 2017 7:29AM in ANTS Memory Profiler 8
Sorry for the length of this question.

I have developed a complex component that is used in a machine controller running windows embedded compact.
Whilst developers are debugging an application that uses my component they are complaining that their executable is not stopping when shut down via their development IDE.
They have correctly identified (confirmed) my component as the cause.
I am using memory profiler to investigate cause; I am seeing some interesting result during profiling but am struggling to interpret them, and do not know if it a code smell or just normal framework behaviour.

The component is a C# winform dll(All managed code) instanciated via a VB.NET singleton interface method (non COM) from compact framework VB.NET all residing in the same app domain

I have a custom thread pool queue like this (because we are running on compact .net framework 3.5)
    public class ThreadPoolQueue
    {
        public delegate void Action(); //roll your own because action with no args was .NET full 3.5 and we are using compact embedded.

        private WorkerThread[] _workers;
        private Queue<Action> _itemQ = new Queue<Action>();
        private readonly object _locker = new object();

When my component is started I see in the instance list an entry for threadpoolqueue+Action[] (the Queue<Action> _itemQ) with the correct values and, viewing its instance retention graph Queue<Action> is correctly rooted to a GCHandle via the threadpoolqueue (distance 5)
but I also see a second entry for the same threadpoolqueue+Action[] but this is rooted to a GCHandle only via an Object[] with size 16 bytes, and no instance values. (distance 1)
When I hover over the GC Handle it says: "object[] is GC root because it has been designated a GCHandle via GCHAndle.Alloc()"
I have seen this on other system.collections (Queues, Lists<T> where T is custom object) so I am assuming that it is an internal framework pointer to the same, Is this correct or could this be a reference in my code that I am not releasing correclty?

Because the exteranl developers were experiencing these issues I wonder if it was down to GC not collecting so I have set up a test harness that mimics the application have tried some explicit disposal of the component
(yes I know I should not have to on managed code!!, but I think this situation might call for it?)

When my component is explicitly disposed (although the main application "test harness" is not stopped because I need to take another snapshot) when I do this the only object that remains in the class list from my component is the
second threadpoolqueue+Action[] entry.

I have also tried the naughty of forcing the GC with (have I done this correctly?):
        GC.Collect()
        GC.SuppressFinalize(Me) 'I don't want to queue me (the main app) finaliser until I know my component has been totally collected
        GC.WaitForPendingFinalizers()

Can I find out easily (by cross reference) what the object Object[] that is referencing this second entry is (the values list for it give me no clues) but its got to be in the list of the other thousands of Object[] objects somewhere?

Could this remaining reference to my component be the cause of the dll's not being freed up? is there anything I can do to free up this reference or is this only going to happen when the main app is shut down

or is it just a herring that is very red!?

Thanks

Martin S
Tagged:

Comments

  • Options
    Hi Martin,

    Thanks for getting in touch.

    Because this problem is specific to your setup, it'll need dedicated investigation on log files by one of our Product Support Engineers. This service comes with one of our support packages.

    Can one of team get in touch with you directly to discuss the options?
Sign In or Register to comment.