Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Large object heap waste

Tags:

c#

.net

I noticed that my application runs out of memory quicker than it should. It creates many byte arrays of several megabytes each. However when I looked at memory usage with vmmap, it appears .NET allocates much more than needed for each buffer. To be precise, when allocating a buffer of 9 megabytes, .NET creates a heap of 16 megabytes. The remaining 7 megabytes cannot be used to create another buffer of 9 megabytes, so .NET creates another 16 megabytes. So each 9MB buffer wastes 7MB of address space!

Here's a sample program that throws an OutOfMemoryException after allocating 106 buffers in 32-bit .NET 4:

using System.Collections.Generic;

namespace CSharpMemoryAllocationTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var buffers = new List<byte[]>();
            for (int i = 0; i < 130; ++i)
            {
                buffers.Add(new byte[9 * 1000 * 1024]);
            }

        }
    }
}

Note that you can increase the size of the array to 16 * 1000 * 1024 and still allocate the same amount of buffers before running out of memory.

VMMap shows this:

enter image description here

Also note how there's an almost 100% difference between the total Size of the Managed Heap and the total Commited size. (1737MB vs 946MB).

Is there a reliable way around this problem on .NET, i.e. can I coerce the runtime into allocating no more than what I actually need, or maybe much larger Managed Heaps that can be used for several contiguous buffers?

like image 633
Asik Avatar asked Oct 29 '14 17:10

Asik


People also ask

What is the large object heap?

If an object is greater than or equal to 85,000 bytes in size, it's considered a large object. This number was determined by performance tuning. When an object allocation request is for 85,000 or more bytes, the runtime allocates it on the large object heap.

Why is a large object heap bad?

The worst case scenario. The design of the Large Object Heap means that its' worse case will occur when the short-lived arrays are large and can vary in size a bit, and if the longer-lived arrays are small.

What is small object heap?

Small Object Heap has generations that are checked from time to time. At the end of collection this heap is fragmented so it need to be compacte. If Large Objects were in this heep it would take long time for defragmentation.

What is heap in garbage collection?

Java objects reside in an area called the heap. The heap is created when the JVM starts up and may increase or decrease in size while the application runs. When the heap becomes full, garbage is collected. During the garbage collection objects that are no longer used are cleared, thus making space for new objects.


1 Answers

Internally the CLR allocates memory in segments. From your description it sounds like the 16 MB allocations are segments and your arrays are allocated within these. The remaining space is reserved and not really wasted under normal circumstances, as it will be used for other allocations. If you don't have any allocation that will fit within the remaining chunks these are essentially overhead.

As your arrays are allocated using contiguous memory you can only fit a single of those within a segment and hence the overhead in this case.

The default segment size is 16 MB, but if you allocation is larger than that the CLR will allocate segments that are larger. I'm not aware of the details, but e.g. if I allocate 20 MB Wmmap shows me 24 MB segments.

One way to reduce the overhead is to make allocations that fit with the segment sizes if possible. But keep in mind that these are implementation details and could change with any update of the CLR.

like image 198
Brian Rasmussen Avatar answered Sep 21 '22 15:09

Brian Rasmussen