Understanding .NET GC and OutOfMemory Exceptions
.net, garbage-collection, out-of-memory
Solution
Here are several points which, taken together, hopefully will give you enough information to answer your question:
- In spite of it's name, OutOfMemory exceptions are just as likely to mean you are out of Address Space as physical RAM.
- GC.Collect does not collect all outstanding RAM. Garbage collections in .Net are non-deterministic, meaning there is no way to force the runtime to clean up all your RAM.
- The garbage collector in .Net is generational, meaning when an object survives collection it moves up to a higher generation, making it even less likely to be collected.
- By the time your OutOfMemory exception is thrown, your array has probably already survived a few collection attempts or was even moved to the LargeObjectHeap.
- Array sizes are fixed. To add a new element to an array you must completely re-allocate the array. (You might get better test results using a structure like a list).
Problem
I'm troubleshooting an OutOfMemory exception in my .NET 2.0 Windows Service application. To understand the issue better I began by writing a simple .NET WinForm test app that generates an OOM Exception by building an ArrayList until an OOM Exception is thrown. The exception is caught and logged and I can click on a form button to run the OOME again. The strange thing I found was on the 4th run, the amount of memory consumed before the next OOME was roughly half. The results listed below are consistent every time I run this. Eyeballing TaskManager also confirms the behavior. Unfortunately, Perfmon froze up when trying to get better stats. Can someone explain why the memory limit is lowered after 3 runs? My understanding of GC is fairly shallow. You can also see I ran a GC.Collect() after a few more runs but it didn't help with the lowered limit. UPDATE: I also found a big difference using a const string vs a new object for each arraylist item. Code is simply: ``` const string TEST_TEXT = "xxxxxxxxxx"; ArrayList list = new ArrayList(); while (true) { list.Add(TEST_TEXT); } ``` Start Loop: memory 10,350,592 - OOM Exception Thrown - Array Size: 134,217,728 End Loop: memory 550,408,192 Start Loop: memory 550,731,776 - OOM Exception Thrown - Array Size: 134,217,728 End Loop: memory 551,682,048 Start Loop: memory 551,813,120 - OOM Exception Thrown - Array Size: 134,217,728 End Loop: memory 551,772,160 Start Loop: memory 551,903,232 - OOM Exception Thrown - Array Size: 67,108,864 End Loop: memory 282,869,760 Start Loop: memory 283,004,928 - OOM Exception Thrown - Array Size: 67,108,864 End Loop: memory 282,910,720 GC.Collect manually triggered Start Loop: memory 14,245,888 - OOM Exception Thrown - Array Size: 67,108,864 End Loop: memory 283,344,896