Delen via


Out of memory! Are you nuts!?

I may have said this before (my memory's not what it was prior to decade number 4), but the most common issues I debug are memory issues. These range from high memory issues (categorized as 800MB of more memory in use by the worker process) to OutOfMemory exceptions, or OOM. High memory cases don't usually accompany any questions from customers other than "what the heck is taking so much memory?", but OOM conditions are often accompanied by "Why am I seeing OOM when the process is using 1GB of memory on a box with 4GB of memory available?" That's a good question, and fortunately, that question has a good answer as well.

Before we go into why you might see an OOM exception, you first need to understand the basics of how we allocate memory in the .NET world. We allocate memory in large contiguous blocks. Any objects you create are created in our heaps that are located within the memory segments we've allocated. As long as there is sufficient free space in the managed heap for your object, we won't allocate more memory from the OS. As objects are freed from gen 0, 1, and 2, we compact the heap so that you don't run into any problems with memory fragmentation in those heaps. The large object heap (LOH), which is where any object that's 85K or larger lives, is never compacted. However, we do maintain a list of free blocks in the LOH segments, and we'll reuse free blocks if we can. Therefore, fragmentation in the LOH is rarely an issue.

With that out of the way, suppose you need to allocate an object that is 40K in size and we don't have enough memory on the gen 0 heap to create that object. We'll then go to the OS and attempt to allocate another contiguous segment. If we're unable to get a segment of contiguous memory from the OS, we'll throw an OOM exception.

Another scenario: suppose that GC runs and we free all of the objects within a particular segment. We will then release that segment back to the OS. Now let's say that 5 minutes later, we need to grow the heap again. We go back to the OS to get a new segment, but some other process has placed a 1K allocation right at the beginning of that segment that we released. What happens? Well, if that 1k allocation fragments your memory and we're unable to find contiguous space . . . you guessed it. An OOM occurs.

So how do you avoid seeing this kind of thing? The first thing you can do is try and avoid a high memory situation. Almost all of the OOM cases we see involve high memory as well. That's because as you approach 80% of available memory for the process (and that's 2GB on a 32-bit machine without the 3GB switch enabled), the likelihood of seeing an OOM begins to increase exponentially. The reason for this (based on the information above) is pretty obvious. If you have reached the 80% mark, the chances of us finding a large, contiguous chunk of memory go down pretty substantially due to fragmentation. How do you avoid a high memory situation? There are a lot of answers to that question, but a few are:

  • Don't create a large number of objects on a per-request basis
  • Don't store large objects in Session
  • Don't cache user-specific data
  • Call Dispose() on objects that provide a Dispose() method
  • Call Marshal.ReleaseComObject in a loop on your COM objects (FinalReleaseComObject without the loop in 2.0)

I don't mean for that to be an exhaustive list, but you get the drift.

Another thing that you want to do to avoid OOM situations is to avoid fragmentation. If system memory is fragmented, it becomes more difficult for the CLR to find contiguous memory to grow the managed heap. There are also a lot of causes of memory fragmentation, but I'd have to say that one of the most common we see is caused by dynamic assemblies. (See my blog entry on the Debug attribute.) Other causes of dynamic assemblies are:

  • XML serialization (We have an article on this)
  • Script blocks in XSL transforms (We have an article on this, too)
  • Heavy use of regular expressions
  • Creating your own dynamic assemblies en masse

There are a lot of other reasons for fragmentation as well, but these are among the most common.

I hope this helps to explain why OOM conditions occur and how you can avoid them.

Comments

  • Anonymous
    April 16, 2006
    you wrote:
    "There are also a lot of causes of memory fragmentation, but I'd have to say that one of the most common we see is caused by dynamic assemblies. (See my blog entry on the Debug attribute.) Other causes of dynamic assemblies are: ... Heavy use of regular expressions"

    can you please explain the reason why regex cause this issue

  • Anonymous
    April 21, 2006
    Regular expressions get compiled into temporary assemblies prior to being executed.

  • Anonymous
    May 06, 2006
    first of all, thanks for answering.
    "Regular expressions get compiled into temporary assemblies prior to being executed."
    i have read about it, but couldn't find in which cases this happens.
    i know for sure that using the option "RegexOptions.Compiled" will cause a temporary assembly.
    i guess not ALL Regex objects compile to temporary assemblies, but i want to be sure for which cases it doesn't (like using the Regex static functions for example)

    thanks

  • Anonymous
    July 14, 2008
    Hi James, Thanks for the thoughts on OOM problems.  You mentioned that temporary assembiles contibute to OOM problems.  I am creating temporary assembiles when I compile user defined methods to create a scripting language.  On a 4GB win Server 2003 system, I start getting error if I create processes with less than 1.5GB of available memory. Question:  What test can I run to determine that I am getting close to an OOM condition?  How about My.Computer.Info.AvailablePhysicalMemory?  Is there a better property to test? Thank you very much, Tom

  • Anonymous
    July 18, 2008
    Hi, Tom. It's not that simple. You'll get an OOM anytime that the CLR attempts to allocate more memory for the managed heap and it's unable to get the necessary amount of contiguous memory. Your best bet is to make sure that you don't do things that are known causes of OOM. Jim

  • Anonymous
    February 04, 2009
    The comment has been removed

  • Anonymous
    February 05, 2009
    The comment has been removed

  • Anonymous
    February 05, 2009
    Thanks Jim, I 'll Try and give you answer !