C# – Reducing the amount of threads in a .NET application

cmemorymultithreading

I have a medium-sized process viewer which uses around ~40MB of private memory on Windows Vista. The problem is that people always compare this number to the amount of memory used by Process Explorer and similar, unmanaged tools.

I've noticed that when my program is idle, there are 13 running threads:

  • One RPC thread (RPCRT4.dll!ThreadStartRoutine)
  • One COM-related thread (ole32.dll!CoRegisterSurrogateEx+0x35e0)
  • Two ntdll threads (ntdll.dll!TppWorkerThread, ntdll.dll!TppWaiterpThread)
  • The main GUI thread
  • A timer thread (used by the CLR)
  • The gate thread (CLR)
  • The debugger thread (CLR)
  • 4 worker threads (mscorwks.dll!Thread::intermediateThreadProc)
  • And finally a GDI+ background thread (gdiplus.dll!BackgroundThreadProc)

How can I get rid of some of these threads, freeing thread stack memory (1MB each)? ThreadPool.GetAvailableThreads tells me that there are 0 worker threads running, but there are 3 "intermediateThreadProc" threads. Could using the service manager API have anything to do with the RPC thread? (It makes RPC calls.)

Best Answer

13 threads is pretty low. Unfortunately, you won't be able to get rid of most of these threads without cutting functionality.

Getting rid of RPC & COM is most likely not possible for a managed app, and the CLR threads all seem to be doing something useful. I'm guessing you're using GDI+ (probably via System.Drawing.) Even though there are 0 worker threads running, the threadpool has the threads "on standby", ready to start. You don't want posting a work item to have to incur the overhead of creating a new thread in an idle process.

Even though you may be using 40 MB of private memory, this is most likely not due to the number of threads. Even if each thread was fully using it's 1 MB of default stack (which they're definitenly not, most of the stack is reserved but not committed and won't show up as private bytes), that is only 13 MB of the 40 MB you're seeing. Can you use CLR Profiler to see what allocations your application is doing?