-1

I have an application which need to check db for every 30secons to check a particular record has updated or not. I use background thread for that. The problem is memory usage of application is continuously increase when I check it in memory profiler. Here is the code

Form1:Base

Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(Check));
t.IsBackground = true;
t.Start();

public void Check() {
            bool isUpdate = false;
            while (!isUpdate)
            {
                DataTable _data = CheckRecord();
                if (_data.Rows.Count > 0)
                {
                    isUpdate = true;
                }
                else
                {
                    Thread.Sleep(30000);
                }
            }
        }

public DataTable CheckRecord(){
return CHANNEL.GetData();
}

Form1 inherit base form

Base:Form

ChannelFactory<ServiceClass> temp= new ChannelFactory<ServiceClass>("AAA");
ServiceClass ss=null;

public ServiceClass CHANNEL
{
    get {
        if(ss==null)
            ss=temp.CreateChannel();
        return ss;
    }
    }
test
  • 1
  • 1
  • Firstly the thread itself needs memory. What *might be* the cause for a *continuous* increase though is `CheckRecord`. Are you creating a big data table? The GC may not collect former `_data` objects as long there is enough memory left. There might therefore be a lot of `DataTable` instances in memory, even though they're not reachable anymore. Are you able to check this with your profiler? – Matthias Meid Aug 13 '13 at 09:19
  • I agree with @MatthiasMeid - you don't explicitly destroy your `DataTable` therefore when you perform the next check you effectively *orphan* it each time and if the CG doesn't hit it before your next check your memory usage will continue to go up. If you aren't using `DataTable` I would return the count from the DB rather than the data itself. – James Aug 13 '13 at 09:25
  • Well, be specific, what did the memory profiler tell you about the object(s) that are not getting garbage collected? It can't be DataTable objects. – Hans Passant Aug 13 '13 at 09:28
  • Show the code for `CheckRecord` – leppie Aug 13 '13 at 09:30
  • @James: "Orphaning" the `DataTable` makes it eligible for garbage collection so that should not be the cause of increased memory pressure. – Martin Liversage Aug 13 '13 at 09:31
  • 1
    @MartinLiversage Yep it does, but that doesn't mean it's going to be collected *immediately*. AFAIK there is no guarantee when an object is going to be GC'd, the GC will only clear the "orphaned" objects on the next sweep and that's generally only triggered when it needs to re-claim RAM. Therefore it is a possibility that it's hanging around when it's not needed (I am just speculating though, I could be wrong). – James Aug 13 '13 at 09:38
  • You're not disposing the instance created by ss=temp.CreateChannel(); – Luis Filipe Aug 13 '13 at 10:46
  • You should use a `Timer` to periodically check things as it do not allocate a new thread. – jgauffin Aug 13 '13 at 11:37
  • @LuisFilipe how can i dispose it, can you provide example – test Aug 13 '13 at 12:48
  • @test As far as i can remember the instance returned from CreateChannel implements the IDisposable interface. If so, you should (must) invoke the Dispose method as soon as you don't need the instance. you may read more here http://coding.abel.nu/2011/12/idisposable-and-using-in-c/ – Luis Filipe Aug 13 '13 at 13:03
  • While you definitely should call `Dispose` on an instance that implements `IDisposable` when you no longer need the instance, the finalizer of the instance (if properly implemented) will still make sure that the non-managed resources are freed during garbage collection. However, if the garbage collector is unaware of the additional memory pressure the unmanaged resources are using the instance may sit on the gen 1 or 2 heap for a long time without getting released and finalized and this may appear to be a memory leak. Also, having to run finalizers during GC is bad for performance. – Martin Liversage Aug 13 '13 at 13:21
  • Don't use a sleep loop in a thread. Set a timer that fires every 30 seconds, and do the check in the timer's event handler. Note that this doesn't address your memory concerns, but it does make for a cleaner design. – Jim Mischel Aug 13 '13 at 13:34
  • What "memory profiler" are you using to profile the application's memory usage? Please be more specific about the raw results it's giving you so we can make sure our answers are relevant to the actual situation. – Sam Harwell Aug 13 '13 at 14:06

3 Answers3

1

With the provided information it is not possible to answer your question. However, to troubleshoot memory leaks you have a few options:

  • Does the memory usage increase go away if you remove the code executed by the thread? If not then you have to look for a leak somewhere else in your code.

  • Most likely the leak is not managed memory because it is garbage collected. You can verify this by monitoring the performance counter .NET CLR Memory -> # Bytes in all Heaps. If this counter increases significantly while your program is running you are "leaking" managed memory in the sense that you have some active data structure that keeps growing in size while not being eligible for garbage collection.

  • Assuming that you have ruled out a managed "leak" then you will have to look for an unmanaged leak. Does you code call some interop API that requires that you clean up? In your code the only possibility seems to be CheckRecord which you should inspect to learn if that is the source of the leak.

Looking at your code it seems that either you have a bug or there is a typo:

public void Check() {
  bool isUpdate = false;
  while (isUpdate) {
    ...
  }
}

Because isUpdate is false the while loop will never be entered and Check will return immediately terminating the thread.

Martin Liversage
  • 104,481
  • 22
  • 209
  • 256
0

You forgot to call Dispose() on the DataTable returned by GetData(). Here is a good answer related to why you need to call Dispose():

Do I need to call Dispose() on managed objects?

Community
  • 1
  • 1
Sam Harwell
  • 97,721
  • 20
  • 209
  • 280
  • `Dispose()` on `DataTable` and `DataSet` do absolutely nothing: http://stackoverflow.com/a/913286/70386 – jgauffin Aug 13 '13 at 11:39
0

The problem is that you're not disposing the instance created by

ss=temp.CreateChannel();

Because the created instance implements the IDisposable interface you should (must) invoke the Dispose() method as soon as you don't need the instance. you may read more here

Take special note about the using keyword to help you disposing your instance

Luis Filipe
  • 8,488
  • 7
  • 48
  • 76