Java and .NET heap overhead

2019-07-02 11:03发布

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.

3条回答
Viruses.
2楼-- · 2019-07-02 11:17

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.

查看更多
老娘就宠你
3楼-- · 2019-07-02 11:19

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.

查看更多
一纸荒年 Trace。
4楼-- · 2019-07-02 11:22

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.

查看更多
登录 后发表回答