Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 132311
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 11, 20262026-05-11T06:14:33+00:00 2026-05-11T06:14:33+00:00

I appear to have a memory leak in this piece of code. It is

  • 0

I appear to have a memory leak in this piece of code. It is a console app, which creates a couple of classes (WorkerThread), each of which writes to the console at specified intervals. The Threading.Timer is used to do this, hence writing to the console is performed in a separate thread (the TimerCallback is called in a seperate thread taken from the ThreadPool). To complicate matters, the MainThread class hooks on to the Changed event of the FileSystemWatcher; when the test.xml file changes, the WorkerThread classes are recreated.

Each time the file is saved, (each time that the WorkerThread and therefore the Timer is recreated), the memory in the Task Manager increases (Mem Usage, and sometimes also VM Size); furthermore, in .Net Memory Profiler (v3.1), the Undisposed Instances of the WorkerThread class increases by two (this may be a red herring though, because I’ve read that .Net Memory Profiler had a bug whereby it struggled to detect disposed classes.

Anyway, here’s the code – does anyone know what’s wrong?

EDIT: I’ve moved the class creation out of the FileSystemWatcher.Changed event handler, meaning that the WorkerThread classes are always being created in the same thread. I’ve added some protection to the static variables. I’ve also provided threading information to show more clearly what’s going on, and have been interchanging using the Timer with using an explicit Thread; however, the memory is still leaking! The Mem Usage increases slowly all the time (is this simply due to extra text in the console window?), and the VM Size increases when I change the file. Here is the latest version of the code:

EDIT This appears to be primarily a problem with the console using up memory, as you write to it. There is still a problem with explicitly written Threads increasing the memory usage. See my answer below.

class Program {     private static List<WorkerThread> threads = new List<WorkerThread>();      static void Main(string[] args)     {         MainThread.Start();      } }  public class MainThread {     private static int _eventsRaised = 0;     private static int _eventsRespondedTo = 0;     private static bool _reload = false;     private static readonly object _reloadLock = new object();     //to do something once in handler, though     //this code would go in onStart in a windows service.     public static void Start()     {         WorkerThread thread1 = null;         WorkerThread thread2 = null;          Console.WriteLine('Start: thread ' + Thread.CurrentThread.ManagedThreadId);         //watch config         FileSystemWatcher watcher = new FileSystemWatcher();         watcher.Path = '../../';         watcher.Filter = 'test.xml';         watcher.EnableRaisingEvents = true;         //subscribe to changed event. note that this event can be raised a number of times for each save of the file.         watcher.Changed += (sender, args) => FileChanged(sender, args);          thread1 = new WorkerThread('foo', 10);         thread2 = new WorkerThread('bar', 15);          while (true)         {             if (_reload)             {                 //create our two threads.                 Console.WriteLine('Start - reload: thread ' + Thread.CurrentThread.ManagedThreadId);                 //wait, to enable other file changed events to pass                 Console.WriteLine('Start - waiting: thread ' + Thread.CurrentThread.ManagedThreadId);                 thread1.Dispose();                 thread2.Dispose();                 Thread.Sleep(3000); //each thread lasts 0.5 seconds, so 3 seconds should be plenty to wait for the                                      //LoadData function to complete.                 Monitor.Enter(_reloadLock);                 thread1 = new WorkerThread('foo', 10);                 thread2 = new WorkerThread('bar', 15);                 _reload = false;                 Monitor.Exit(_reloadLock);             }         }     }      //this event handler is called in a separate thread to Start()     static void FileChanged(object source, FileSystemEventArgs e)     {         Monitor.Enter(_reloadLock);         _eventsRaised += 1;         //if it was more than a second since the last event (ie, it's a new save), then wait for 3 seconds (to avoid          //multiple events for the same file save) before processing         if (!_reload)         {             Console.WriteLine('FileChanged: thread ' + Thread.CurrentThread.ManagedThreadId);             _eventsRespondedTo += 1;             Console.WriteLine('FileChanged. Handled event {0} of {1}.', _eventsRespondedTo, _eventsRaised);             //tell main thread to restart threads             _reload = true;         }         Monitor.Exit(_reloadLock);     } }  public class WorkerThread : IDisposable {     private System.Threading.Timer timer;   //the timer exists in its own separate thread pool thread.     private string _name = string.Empty;     private int _interval = 0;  //thread wait interval in ms.     private Thread _thread = null;     private ThreadStart _job = null;      public WorkerThread(string name, int interval)     {         Console.WriteLine('WorkerThread: thread ' + Thread.CurrentThread.ManagedThreadId);         _name = name;         _interval = interval * 1000;         _job = new ThreadStart(LoadData);         _thread = new Thread(_job);         _thread.Start();         //timer = new Timer(Tick, null, 1000, interval * 1000);     }      //this delegate instance does NOT run in the same thread as the thread that created the timer. It runs in its own     //thread, taken from the ThreadPool. Hence, no need to create a new thread for the LoadData method.     private void Tick(object state)     {         //LoadData();     }      //Loads the data. Called from separate thread. Lasts 0.5 seconds.     //     //private void LoadData(object state)     private void LoadData()     {         while (true)         {             for (int i = 0; i < 10; i++)             {                 Console.WriteLine(string.Format('Worker thread {0} ({2}): {1}', _name, i, Thread.CurrentThread.ManagedThreadId));                 Thread.Sleep(50);             }             Thread.Sleep(_interval);         }     }      public void Stop()     {         Console.WriteLine('Stop: thread ' + Thread.CurrentThread.ManagedThreadId);         //timer.Dispose();         _thread.Abort();     }       #region IDisposable Members      public void Dispose()     {         Console.WriteLine('Dispose: thread ' + Thread.CurrentThread.ManagedThreadId);         //timer.Dispose();         _thread.Abort();     }      #endregion } 
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. 2026-05-11T06:14:34+00:00Added an answer on May 11, 2026 at 6:14 am

    Well, having had some time to look into this again, it appears that the memory leak is a bit of a red herring. When I stop writing to the console, the memory usage stops increasing.

    However, there is a remaining issue in that every time I edit the test.xml file (which fires the Changed event on the FileSystemWatcher, whose handler sets flags that cause the worker classes to be renewed and therefore threads/timers to be stopped), the memory increases by about 4K, providing that I am using explicit Threads, rather Timers. When I use a Timer, there is no problem. But, given that I would rather use a Timer than a Thread, this is no longer an issue to me, but I would still be interested in why it is occuring.

    See the new code below. I’ve created two classes – WorkerThread and WorkerTimer, one of which uses Threads and the other Timers (I’ve tried two Timers, the System.Threading.Timer and the System.Timers.Timer. with the Console output switched on, you can see the difference that this makes with regards to which thread the tick event is raised on). Just comment/uncomment the appropriate lines of MainThread.Start in order to use the required class. For the reason above, it is recommended that the Console.WriteLine lines are commented out, except when you want to check that everything is working as expected.

    class Program {     static void Main(string[] args)     {         MainThread.Start();      } }  public class MainThread {     private static int _eventsRaised = 0;     private static int _eventsRespondedTo = 0;     private static bool _reload = false;     private static readonly object _reloadLock = new object();     //to do something once in handler, though     //this code would go in onStart in a windows service.     public static void Start()     {         WorkerThread thread1 = null;         WorkerThread thread2 = null;         //WorkerTimer thread1 = null;         //WorkerTimer thread2 = null;          //Console.WriteLine('Start: thread ' + Thread.CurrentThread.ManagedThreadId);         //watch config         FileSystemWatcher watcher = new FileSystemWatcher();         watcher.Path = '../../';         watcher.Filter = 'test.xml';         watcher.EnableRaisingEvents = true;         //subscribe to changed event. note that this event can be raised a number of times for each save of the file.         watcher.Changed += (sender, args) => FileChanged(sender, args);          thread1 = new WorkerThread('foo', 10);         thread2 = new WorkerThread('bar', 15);         //thread1 = new WorkerTimer('foo', 10);         //thread2 = new WorkerTimer('bar', 15);          while (true)         {             if (_reload)             {                 //create our two threads.                 //Console.WriteLine('Start - reload: thread ' + Thread.CurrentThread.ManagedThreadId);                 //wait, to enable other file changed events to pass                 //Console.WriteLine('Start - waiting: thread ' + Thread.CurrentThread.ManagedThreadId);                 thread1.Dispose();                 thread2.Dispose();                 Thread.Sleep(3000); //each thread lasts 0.5 seconds, so 3 seconds should be plenty to wait for the                  //LoadData function to complete.                 Monitor.Enter(_reloadLock);                 //GC.Collect();                 thread1 = new WorkerThread('foo', 5);                 thread2 = new WorkerThread('bar', 7);                 //thread1 = new WorkerTimer('foo', 5);                 //thread2 = new WorkerTimer('bar', 7);                 _reload = false;                 Monitor.Exit(_reloadLock);             }         }     }      //this event handler is called in a separate thread to Start()     static void FileChanged(object source, FileSystemEventArgs e)     {         Monitor.Enter(_reloadLock);         _eventsRaised += 1;         //if it was more than a second since the last event (ie, it's a new save), then wait for 3 seconds (to avoid          //multiple events for the same file save) before processing         if (!_reload)         {             //Console.WriteLine('FileChanged: thread ' + Thread.CurrentThread.ManagedThreadId);             _eventsRespondedTo += 1;             //Console.WriteLine('FileChanged. Handled event {0} of {1}.', _eventsRespondedTo, _eventsRaised);             //tell main thread to restart threads             _reload = true;         }         Monitor.Exit(_reloadLock);     } }  public class WorkerTimer : IDisposable {     private System.Threading.Timer _timer;   //the timer exists in its own separate thread pool thread.     //private System.Timers.Timer _timer;     private string _name = string.Empty;      /// <summary>     /// Initializes a new instance of the <see cref='WorkerThread'/> class.     /// </summary>     /// <param name='name'>The name.</param>     /// <param name='interval'>The interval, in seconds.</param>     public WorkerTimer(string name, int interval)     {         _name = name;         //Console.WriteLine('WorkerThread constructor: Called from thread ' + Thread.CurrentThread.ManagedThreadId);         //_timer = new System.Timers.Timer(interval * 1000);         //_timer.Elapsed += (sender, args) => LoadData();         //_timer.Start();         _timer = new Timer(Tick, null, 1000, interval * 1000);     }      //this delegate instance does NOT run in the same thread as the thread that created the timer. It runs in its own     //thread, taken from the ThreadPool. Hence, no need to create a new thread for the LoadData method.     private void Tick(object state)     {         LoadData();     }      //Loads the data. Called from separate thread. Lasts 0.5 seconds.     //     private void LoadData()     {         for (int i = 0; i < 10; i++)         {             //Console.WriteLine(string.Format('Worker thread {0} ({2}): {1}', _name, i, Thread.CurrentThread.ManagedThreadId));             Thread.Sleep(50);         }     }      public void Stop()     {         //Console.WriteLine('Stop: called from thread ' + Thread.CurrentThread.ManagedThreadId);         //_timer.Stop();         _timer.Change(Timeout.Infinite, Timeout.Infinite);         //_timer = null;         //_timer.Dispose();     }       #region IDisposable Members      public void Dispose()     {         //Console.WriteLine('Dispose: called from thread ' + Thread.CurrentThread.ManagedThreadId);         //_timer.Stop();         _timer.Change(Timeout.Infinite, Timeout.Infinite);         //_timer = null;         //_timer.Dispose();     }      #endregion }  public class WorkerThread : IDisposable {     private string _name = string.Empty;     private int _interval = 0;  //thread wait interval in ms.     private Thread _thread = null;     private ThreadStart _job = null;     private object _syncObject = new object();     private bool _killThread = false;      public WorkerThread(string name, int interval)     {         _name = name;         _interval = interval * 1000;         _job = new ThreadStart(LoadData);         _thread = new Thread(_job);         //Console.WriteLine('WorkerThread constructor: thread ' + _thread.ManagedThreadId + ' created. Called from thread ' + Thread.CurrentThread.ManagedThreadId);         _thread.Start();     }      //Loads the data. Called from separate thread. Lasts 0.5 seconds.     //     //private void LoadData(object state)     private void LoadData()     {         while (true)         {             //check to see if thread it to be stopped.             bool isKilled = false;              lock (_syncObject)             {                 isKilled = _killThread;             }              if (isKilled)                 return;              for (int i = 0; i < 10; i++)             {                 //Console.WriteLine(string.Format('Worker thread {0} ({2}): {1}', _name, i, Thread.CurrentThread.ManagedThreadId));                 Thread.Sleep(50);             }             Thread.Sleep(_interval);         }     }      public void Stop()     {         //Console.WriteLine('Stop: thread ' + _thread.ManagedThreadId + ' called from thread ' + Thread.CurrentThread.ManagedThreadId);         //_thread.Abort();         lock (_syncObject)         {             _killThread = true;         }         _thread.Join();     }       #region IDisposable Members      public void Dispose()     {         //Console.WriteLine('Dispose: thread ' + _thread.ManagedThreadId + ' called from thread ' + Thread.CurrentThread.ManagedThreadId);         //_thread.Abort();         lock (_syncObject)         {             _killThread = true;         }         _thread.Join();     }      #endregion } 
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Ask A Question

Stats

  • Questions 83k
  • Answers 83k
  • Best Answers 0
  • User 1
  • Popular
  • Answers
  • Editorial Team

    How to approach applying for a job at a company ...

    • 7 Answers
  • Editorial Team

    How to handle personal stress caused by utterly incompetent and ...

    • 5 Answers
  • Editorial Team

    What is a programmer’s life like?

    • 5 Answers
  • Editorial Team
    Editorial Team added an answer It seems like you might want datetime's "time" type, which… May 11, 2026 at 4:50 pm
  • Editorial Team
    Editorial Team added an answer This has reminded me of the first HTTP server I… May 11, 2026 at 4:50 pm
  • Editorial Team
    Editorial Team added an answer It turns out that the following statement causes IE to… May 11, 2026 at 4:50 pm

Related Questions

I'm having a problem with an application hanging and giving me the default Please
I have been working on a web services related project for about the last
I was reading Java Platform Performance (sadly the link seems to have disappeared from
This is either ridiculously simple, or too complex . . . . In our

Trending Tags

analytics british company computer developers django employee employer english facebook french google interview javascript language life php programmer programs salary

Top Members

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.