Java and .NET heap overhead

Java and .NET heap overhead … here is a solution to the problem.

Java and .NET heap overhead

I understand how heaps and garbage collectors work: garbage collection happens in generation, memory allocation happens sequentially, free/unused space is compressed during garbage collection by moving data and forming continuous blocks, etc.

Are there headers that allocate memory blocks, how big are they (I’ve heard .NET CLR is 8-16 bytes), are there byte, word, or fourword alignment? I’m interested in anything about JIT (Java) and CLR (.NET Framework or Mono) implementations of x86 and x64 processor architectures.

Best Solution

I believe the header size is two words – one for type references, one for synchronized blocks and other flags. The padding (I believe) is just enough to round the total size to integer words.

For example, a reference type with only “int” requires 12 bytes on x86, as follows:

using System;

public class Foo
{
    int x;

    public Foo(int x)
    {
        this.x = x;
    }
}

public class Test
{
    static void Main(string[] args)
    {
        int length = int.Parse(args[0]);

        Foo x = new Foo(0);
        Foo[] array = new Foo[length];
        // Make sure that JITting the string constructor doesn't
        // change things
        long start = GC.GetTotalMemory(true);
        for (int i=0; i < length; i++)
        {
            array[i] = new Foo(i);
        }
        long end = GC.GetTotalMemory(true);

        GC.KeepAlive(array);
        GC.KeepAlive(x);

        decimal totalDecimal = end-start;
        Console.WriteLine(totalDecimal / length);
    }
}

An interesting point – for some reason, an instance of System.Object requires 12 bytes (on x86) instead of the 8 bytes I originally predicted. It’s like the minimum size is 12 bytes, but you get the first four bytes of the actual data for free 🙂

I don’t know why the reported size isn’t exactly an integer, btw – I suspect this has something to do with a little extra memory required per page in the managed heap, or something like that. Sometimes it turns out a little more than 12, sometimes a little below 12 – it seems to depend on the given length. (The previous version of this answer had an error that parsed the first command-line arg but then ignored it.) I’ve fixed it. Anyway, I don’t think this slight inaccuracy has anything to do with the size of a single object in memory.

Related Problems and Solutions