views:

411

answers:

3

I have understanding how heap and garbage collector works: garbage collection happens in generations, memory allocation happens sequentially, during garbage collection free/unused space compacted by shifting data and forming continues block, etc.

Is there any headers for allocated memory chunks are present and how big are they (I heard it’s 8-16 bytes for .NET CLR) and if byte, word or quad-word alignment present? I’m interested in any information for JIT (Java) and CLR (.NET Framework or Mono) implementation for x86 and x64 processor architectures.

A: 

I don't know about Java but for the CLR there is a 1 native word overhead per reference type allocated. On 32 bit systems it will be 4 bytes and 64 bit systems it will be 8 bytes.

JaredPar
its allocated memory. I'm looking how physical heap memory looks like. Usually it's [header][object data][padding][header][object data][padding]....I'm looking for sizes of header and padding.
LicenseQ
??? I just told you the size of the header and you comment asking for the size of the header
JaredPar
Why would you have reference in the header?
LicenseQ
Just plain wrong: there is a 2 native word overhead per reference type, not counting an additional word for each reference to the object.
Qwertie
+2  A: 

I believe the header size is two words - one for the type reference and one for the sync block and other flags. The padding is (I believe) just enough to round the total size up to a whole number of words.

For instance, a reference type with just an "int" in takes 12 bytes on x86, as demonstrated here:

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);
    }
}

One interesting point - for some reason an instance of System.Object takes 12 bytes (on x86) instead of the 8 that I would otherwise have predicted. It's as if the minimum size is 12 bytes, but you get the first four bytes of real data free :)

I don't know why the size reported isn't exactly an integer, btw - I suspect it's something to do with a little bit of extra memory required for per page in the managed heap, or something like that. Sometimes the result is a little bit over 12, sometimes a little bit under 12 - that seems to depend on the length given. (The previous version of this answer had a bug in, where it would parse the first command line arg but then ignore it. I've fixed that.) Anyway, I don't believe this slight inaccuracy has anything to do with the size of an individual object in memory.

Jon Skeet
That is why the question was asked :-)
LicenseQ
"That" being what, exactly? The last bit? That's not related to how big an actual object is - just some other objects being created or freed in the background.
Jon Skeet
"presumably something is going on in the background, but I don't know what..."
LicenseQ
@LicenseQ: As I say, that's not related to the actual size IMO. Will update answer to explain.
Jon Skeet
CLR via C#, by Jeff Richter. I'll see if there's an online article with similar info.
Jon Skeet
EDITED: Your answer is helpful in some sence. Could you also give reference where you got "type reference and one for the sync block" info?
LicenseQ
http://blog.vuscode.com/malovicn/archive/2008/01/13/net-foundations-memory-model-part-2.aspx
Jon Skeet
Also http://www.codeproject.com/KB/cs/net_type_internals.aspx#4
Jon Skeet
I guess "sync block" was keyword to find http://www.oreilly.com.tw/bookcode/JavaTwo_GC.pdf. Thanks
LicenseQ
Well, all my info was about .NET rather than Java - but if it helped you find useful stuff, then great!
Jon Skeet
+1  A: 

A complete answer to the question would actually be rather complicated: the overhead associated with object allocation depends not only on the implementation details of the particular virtual machine, but for example also on the generation that the object happens to be in (in other words, the overhead associated with a particular object can change during the lifetime of the object).

There are few simple utilities that can be used to estimate the overhead for a particular object, but nothing robust (check out for example http://java.sun.com/docs/books/performance/1st_edition/html/JPRAMFootprint.fm.html).

In Java, there is also an interface that might give you the object size including overhead, see http://download-llnw.oracle.com/javase/6/docs/platform/jvmti/jvmti.html#GetObjectSize.

Petr Tuma