8

I have an application that creates lot of threads over time. I noticed that memory usage grows as it runs and eventually runs out of memory. But the same code doesn't leak memory on my coworker's environment. We both have same .net version. I was able to reproduce the issue with the following sample code which doesn't leak on my coworker's laptop but does on my laptop.

public static void Main(string[] args)
{           
    Console.WriteLine("Version " + Environment.Version.ToString());

    if (Environment.Is64BitProcess) 
        Console.WriteLine("64"); 
    else 
        Console.WriteLine("32");

    while(true)
    {
        Thread t = new Thread(() => { Thread.Sleep(1); });
        t.IsBackground = true;
        t.Start();
        Thread.Sleep(1);               
    }
}

When I run the above, it prints the following

Version 4.0.30319.18063
32

In Visual Studio 2012 the target framework for the project is .net framework 4.5. The project leaks memory with following configuration

Project Properties -> Build
    Platform target: Any CPU
    Prefer 32-bit: checked

If I unchecked Prefer 32-bit, it doesn't leak.

Another configuration that leaks memory is

Project Properties -> Build
    Platform target: x86
    Prefer 32-bit: disabled

The resulting executable that leaks on my laptop doesn't leak on my coworker's laptop.

I used CLR Profiler to find memory leaks but it doesn't show anything that's leaking. But I do see that working set in windows resource monitor increases by about 1 MB/sec.

What is causing the memory usage to increase in 32-bit mode on my environment but not my coworker's?

Dave New
  • 38,496
  • 59
  • 215
  • 394
Csharp_user
  • 139
  • 2
  • 5
  • 1
    FWIW when I try this on my PC I get the same behaviour as your colleague (no leak). – Cameron Apr 16 '15 at 19:31
  • And what version(s) does your coworker run? – H H Apr 16 '15 at 19:41
  • 1
    Try using the [umdh tool](https://msdn.microsoft.com/en-us/library/windows/hardware/ff560206%28v=vs.85%29.aspx) (be sure to install the 32-bit Debugging Tools for Windows) to see who's allocating all the memory. Also, what happens if you remove the sleep inside the thread method? – Cameron Apr 16 '15 at 19:41
  • 2
    Check the number of threads using process explorer or task manager. Does it increase? Could be timing. – usr Apr 16 '15 at 20:12
  • 1
    @Thomas Weller: We both have same type of laptop. Same CPU Intel Core i7-3820QM. – Csharp_user Apr 16 '15 at 20:17
  • how do you knows its leaking, how do you know it runs out of memory? – pm100 Apr 16 '15 at 20:23
  • 1
    @Cameron: I'll try umdh and get back to you. Removing Sleep doesn't change anything. It still leaks. – Csharp_user Apr 16 '15 at 20:25
  • @Henk Holterman: We both have same versions and running same executable – Csharp_user Apr 16 '15 at 20:25
  • 1
    @usr: I checked the threads and they are about 5 and they are not increasing. – Csharp_user Apr 16 '15 at 20:26
  • @pm100: Windows Resource Monitor shows memory is growing and eventually my app crashes. – Csharp_user Apr 16 '15 at 20:27
  • @ThomasWeller I'm observing commit, working set. commit, working set and private are increasing. – Csharp_user Apr 16 '15 at 20:32
  • 1
    Please configure WER LocalDumps to write a dump at the time it crashes. Then you can analyze what kind of memory is inside. https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx – Thomas Weller Apr 16 '15 at 20:32
  • 1
    Forget about Working Set - that heavily depends on physical RAM. But Private is good choice. – Thomas Weller Apr 16 '15 at 20:35
  • 1
    Add Handles column to the resource Monitor. If it is working properly you *should* see it increasing steadily and then suddenly dropping occasionally. When I run this code the handles goes up to about 10,000 and then they are released and drops back down to about 1,000. I'd be curious if yours increase much more. – AaronLS Apr 16 '15 at 20:36
  • 2
    I'm really excited to see this resolved. – Thomas Weller Apr 16 '15 at 20:39
  • 1
    Also make sure you are using the newest CLR Profiler(link below). You should see a jigsaw pattern as GC kicks in and releases memory: http://www.microsoft.com/en-us/download/details.aspx?id=16273 – AaronLS Apr 16 '15 at 20:44
  • And here is an article on using WinDbg, which is not a very user friendly tool, but I've used it as a last resort: http://blogs.msdn.com/b/kaevans/archive/2011/04/11/intro-to-windbg-for-net-developers.aspx – AaronLS Apr 16 '15 at 20:46
  • 4
    You used to be able to pretty reliably crash your program with code like this. The Thread class uses a lot of handles but doesn't have a Dispose() method. No more, Microsoft did something about it. You now need to look for other kind of software that's too interested in handles, the shrink-wrapped malware that programmers voluntarily install on their machine. Disable your anti-virus product and try again. – Hans Passant Apr 16 '15 at 20:56
  • @AaronLS I'm running on Windows 7. I don't see any option to add handles column to CPU tab. But I see a list of associated handles for my app and they don't seems to be increasing. – Csharp_user Apr 16 '15 at 21:00
  • 1
    @Csharp_user Sorry was in task manager, not sure in resource monitor. On Windows 7 under Windows Task Manager(Ctrl+Shift+Esc)-> View-> Select Columns...->Handles – AaronLS Apr 16 '15 at 21:07
  • 1
    @AaronLS The handles for the app are under 1000. – Csharp_user Apr 16 '15 at 21:12
  • @ThomasWeller I enabled the local dumps but I don't see it writing to the local dumps. May be I need to restart my computer after registry change. I have the mini dump that is created by windows after the app crashes. Is the mini dump enough for debugging? – Csharp_user Apr 16 '15 at 22:24
  • 1
    You need a full memory dump to debug .NET: http://stackoverflow.com/questions/24874027/how-do-i-take-a-good-crash-dump-for-net/24874028#24874028 – Thomas Weller Apr 16 '15 at 22:33
  • @ThomasWeller I was able to get the dump using VS2012 debug attach process. But VS2012 doesn't have tools to view the heap. It looks like VS2013 have debugging tools so getting VS2013 ultimate. – Csharp_user Apr 17 '15 at 18:39
  • @AaronLS I installed WinDbg but don't know how to use it. I was able to open the dump generated VS2012. I can open view memory but it's a bunch of bytes – Csharp_user Apr 17 '15 at 18:41
  • Alright, well, it probably won't be easy to learn all the things. Finally you want something like this: http://stackoverflow.com/a/26150591/480982 but you might need some more commands. Perhaps you need to do some research, ask other WinDbg questions or we find some time to collaborate in a chat. That said, Hans Passant has left a comment. And if Hans leaves a comment we should take that serious. But to turn Hans' comment into an answer, we should not simply take it as given. We should learn something and show the way to figure it out step by step. – Thomas Weller Apr 17 '15 at 20:24
  • Running the test app in windows safe mode doesn't leak. But it's leaks in windows normal mode with all services, startups disabled. – Csharp_user Apr 20 '15 at 16:36

2 Answers2

0

I've read all comments and afraid that my comment will be lost there, so try to answer.

Use memory profiler designed for .NET applications, JetBrains dotMemory or ANTS or whatever but WinDBG or Task Manager or other native memory tools.

You can compare how app behaves on your and your colleague's laptops using realtime chart of chosen profiler. I guess you will see that memory usage constantly increases on your laptop - just get a memory snapshot and see how many Thread objects are in memory, what objects take most of the memory and investigate why and by whom are they held in memory.

Ed Pavlov
  • 2,353
  • 2
  • 19
  • 25
-2

You should limit the number of simultaneous threads you are running at the same time and maybe you can using the thread pool, so you can queue threads that are added and exceeding the pool size you define.

https://msdn.microsoft.com/en-us/library/h4732ks0.aspx

Laurent Lequenne
  • 902
  • 5
  • 13