3

I have code that generates threads in a loop. After about a thousand threads, I get an OutOfMemoryException on the thread.Start() call.

Apparently, there is no limit on the amount of threads in de C# app, and my application has only allocated ~87MB of memory (according to the Task Manager).

Why do I get that OutOfMemory exception?

Bart Friederichs
  • 33,050
  • 15
  • 95
  • 195
  • and the remained memory available on the system is? – kennyzx Oct 18 '18 at 09:18
  • 2
    I don't know what number Task Manager is serving up, but every thread consumes 1 MB of reserved (not yet committed) virtual memory, so 1000 of the little devils need 1 GB of reserved VM right off the bat. If this is a toy program it's fine, but if you're actually thinking of solving a problem with thousands of threads, it's best to start thinking of something that scales better (like `Task`s). – Jeroen Mostert Oct 18 '18 at 09:24
  • @kennyzx around 4.5GB – Bart Friederichs Oct 18 '18 at 09:25
  • @JeroenMostert it is not a toy program, and it will not run thousands of threads in production, I am doing some performance / worst case testing now. I am trying to understand what is going on when I get that exception, when there is more than enough memory available according to the Task Manager. – Bart Friederichs Oct 18 '18 at 09:27
  • 1
    Since each thread has 1MB of stack, you may be running out of memory on the original thread,if you have variables holding onto the threads` variables – Hasan Emrah Süngü Oct 18 '18 at 09:30
  • @JeroenMostert That is it... A process can use up to 1GB of memory if it is 32 bit, even there are abundant memory on the system. If compiled as x64, it may use more, IIRC, 3 GB? – kennyzx Oct 18 '18 at 09:30
  • 1
    Are those threads actually doing anything? If not, then yes, this is a toy program, because threads that do nothing would be the *best* case, not the worst. In reality, most programs would be brought to their knees with far fewer than 1000 threads if all of those threads are actually performing work. (If most of them are sitting around idle it's another matter.) Testing how many threads your program can bear is the wrong test -- it implies you're going to rely on threads scaling. They don't. (And yes, I realize this does not actually answer your question directly.) – Jeroen Mostert Oct 18 '18 at 09:30
  • 1
    @kennyzx: a 32-bit process can consume up to 2 GB if not large address aware and the full 4 GB if it is (and .NET sets LAA, if I'm not mistaken). A 64-bit process is not so restricted. Some versions of VS and .NET set the "run as 32-bit" flag by default, some don't. – Jeroen Mostert Oct 18 '18 at 09:32
  • @JeroenMostert the threads are sending something to another server and waiting for a result. I think I should use a `Task` for that now. The 1GB limit could really be the culprit, but why doesn't that show in the Task Manager or Resource Monitor? – Bart Friederichs Oct 18 '18 at 09:34
  • 1
    Task Manager has an option to show more columns ("Details" tab, right click, "Select columns"); it's probably somewhere in one of those. I personally still prefer Process Explorer; Task Manager has improved in recent versions, but still isn't as featured. – Jeroen Mostert Oct 18 '18 at 09:36
  • I don't actually know C#, but the `Thread.start()` method in a certain other programming language that C# imitates will throw an "out-of-memory" exception if there is _any_ reason why the new thread can not be created. The system doesn't actually have to be out of memory. For example, It could be that the OS has a limited number of thread "slots", and the program has tried to exceed that number. – Solomon Slow Oct 18 '18 at 10:30
  • @SolomonSlow: there are [practical limits to the number of threads](https://blogs.technet.microsoft.com/markrussinovich/2009/07/05/pushing-the-limits-of-windows-processes-and-threads/), and you'll hit those way before any theoretical limits, but Windows does not have a fixed limit on the number of threads (there's a theoretical 4B "limit" because thread IDs are 32-bit, but that hardly counts). (Since the question mentions Task Manager, it's safe to assume Windows in this case -- things will be different if you're running .NET somewhere else.) – Jeroen Mostert Oct 18 '18 at 10:34
  • 2
    You got OOM because your program ran out of address space. What Task Manager shows you is not useful, on a demand-paged virtual memory operating system there are multiple measures for memory usage. You did not do enough demanding and paging yet. Commit size is a better measure for address space usage. Use Project > Properties > Compile tab, untick "Prefer 32-bit". You don't prefer it when you think that thousands of threads can make your program better. It increases the address space from 2GB to 8TB or more, you'd run out of commit space first. – Hans Passant Oct 18 '18 at 10:43

0 Answers0