What is the maximum number of timers a program can create?


As MSDN correctly notes, "Timers are a limited global resource." How limited are they? (We're talking about timers created by SetTimer.)

Not as limited as they once were.

Originally, there were eight timers total for the entire system. When there are only eight timers, you have to be very careful not to waste them and to destroy them when they aren't needed.

Windows 3.0 increased this to 32.

Windows 95 increased this to around 2500, although the debug version of Windows got mad at you if a single program created more than 32.

Windows NT 3.1 would create timers until you exhausted the desktop heap. The maximum number of timers depends on what other window manager objects had been created.

Starting with Windows NT 4, the window manager treats timers as User Objects for bookkeeping purposes, so all your timers, windows, menus, and so on fight for space in the per-process 10,000 object limit and the 32,000-ish object limit for a desktop.

As you can see, the precise limit changes over time, so you couldn't count on any particular limit being in effect. Who knows, maybe the limit will change again in a future version of Windows.

These limits are pretty high, but that doesn't mean you can be lazy. Jessica pointed out that the WinForms Timer component is easily leaked "because most people don't know that they have to call Dispose on it." Another thing to check for when you find that you can't create any more timers.

Comments (12)
  1. John says:

    10,000 timers ought to be enough for anybody.

  2. Mike says:

    In general, requiring so many timers is an indication of larger architectural issues in your application.

  3. Wyatt says:

    "Actually it looks like when the garbage collector cleans a WinForms Timer it’ll get cleaned up properly, but if you’re using a lot of timers it’s probably good to .Dispose them explicitly.  As long as you don’t have the Tick event (or any other, such as Disposed) hooked up it should be collected automatically"

    Not if Enabled = true it won’t.  You’ll leak the timer and probably the form it’s on too.  If you dispose of the for you placed it on in the designer, that should take care of it.  And disposing of forms is always a good idea, as other components like MenuItem have a habit of leaking unless disposed too.

  4. Bob says:

    Garbage collection only cleans up RAM – no other resources. If the garbage collector happens to run, you’ll probably get your other resources cleaned up – but there’s absolutely no guarantee as to when that will happen.

    Therefore, if the class is anything but somewhere to store data there’s a fairly good chance that you need to read the documentation to find out how to clean up when you’re finished using the class.

    Of course, with timers this only matters if you’re creating and destroying them at runtime, instead of just sticking a fixed number on forms and leaving them for the entire lifetime of the application.

  5. Dan says:

    "Jessica pointed out that the WinForms Timer component is easily leaked "because most people don’t know that they have to call Dispose on it.""

    BAH I did not know this, now I have to go and patch all my apps.

    Actually it looks like when the garbage collector cleans a WinForms Timer it’ll get cleaned up properly, but if you’re using a lot of timers it’s probably good to .Dispose them explicitly.  As long as you don’t have the Tick event (or any other, such as Disposed) hooked up it should be collected automatically*.

    It might not be cleaned up correctly if the timer is running but I’m not sure.  In any case you wouldn’t normally leave a timer running with an unhooked Tick event**.

    * – Reminds me of the time when there was this robot contest thing where you made a real car automatically drive down a course without any human aid (the course wasn’t known to the contestants ahead of time).  One group programmed their stuff in .NET and complained when it ran out of memory and crashed, complaining of memory leaks.  Turns out they never properly unhooked events on objects they no longer needed to use so the garbage collector  could never clean up.

    ** – All information was garnered through my awesome powers of Reflection!  And possibly a third-party tool.

  6. Miral says:

    If the Timer is added via the designer then it will be disposed automatically with the form, since it gets added to the form’s ‘components’ container.

    The far more frequent leaks come from people not remembering to Dispose their dialogs, or worse, not remembering to Dispose of non-stock Pens and Brushes created for custom painting.

    Less common, but also trap-worthy: if you have a dynamic panel (where you add/remove controls at runtime), you need to remember to Dispose of the controls that you remove (unless you keep a reference around to them and actually add them back in again later on).

    The cardinal rule: if it’s IDisposable, Dispose of it.  (Although just to complicate matters, some objects want to be Closed instead of being Disposed.  And it’s not always obvious from the help pages whether a given object is IDisposable unless you dig right down its inheritance hierarchy.)

  7. Jonathan Pryor says:

    @Bob While the GC only handles memory, the GC will also invoke the object.Finalize() method during collection.  This gives the object a "last minute" opportunity to clean up any non-managed resources (non-GC ram, files, HANDLEs, timers, etc., etc.).

    See:

    http://msdn.microsoft.com/en-us/library/fs2xkftw.aspx

    http://msdn.microsoft.com/en-us/library/b1yfkh5e.aspx

    All types which wrap unmanaged resources should follow the IDisposable convention.  Best case, it’ll inform developers to use ‘using’ blocks or otherwise ensure that resources are released quickly.  Worst case, it’ll give the GC an opportunity to clean up the unmanaged resource.

  8. Drak says:

    If you are using these disposable objects only in a short scope consider using the "Using" (in VB.NET anyway, not sure about C#) feature. This way objects automatically are disposed at the end of the scope (even if an exception happened, or so I am told).

  9. JM says:

    @Miral: The "I don’t know if you’re disposable or not" thing annoys me so much that I’ve gotten into the habit of always writing ((IDisposable) object).Dispose() if .Dispose() is explicitly implemented. That’s only if you can’t use "using", of course.

    I understand the rationale here (that "closing" a connection feels obvious, while calling some obscure .Dispose() method does not) but IMO, it’s far better to clearly communicate the object needs finalization (by exposing .Dispose()) than to make the interface "clean". This also saves a trip to the documentation (or worse, Reflector) to find out if .Close() actually does what you think it does — with .Dispose(), there is no question.

  10. Kevin Eshbach says:

    It’s a shame that all the hype surround these 4th generation languages makes it sound like a programmer won’t experience some of the same basic issues a 3rd generation language does.

  11. Ulric says:

    wait, I though the point of moving to .net is fool proof programming and no leaks..

  12. Kevin Eshbach says:

    The 4th generation languages do save a programmer from dealing with some basic issues such as resizing memory or buffer overflows, but other issues they don’t.

Comments are closed.