0

As far as I know, on 32 bit machine, a Pointer takes 4 bytes (32 bits). But, when I ran CLRProfiler on my application, to my surprise, it shows the memory allocated is 32 bytes for holding just one interface pointer.

Allocated memory for Reference types

You can see from the above pic, that 377910 objects consumed 12 MB, which means 32 bytes per object. Am I missing some thing here?

Servy
  • 202,030
  • 26
  • 332
  • 449
Imran
  • 694
  • 5
  • 12
  • 3
    No, a reference is 4 bytes. Without more information, it's impossible to tell what you were really seeing. – Gabe Sep 04 '12 at 12:36
  • Are you talking about pointers or references here. Pointers are rare in C# (they can only be used in code blocks marked as unsafe) – Rune FS Sep 04 '12 at 12:37
  • 1
    @RuneFS but references are implemented as pointers. – Jon Hanna Sep 04 '12 at 12:43
  • I mean references only. I agree that a reference takes only 4 bytes. But I don't know why CLRProfiler is showing as if it takes 32 bytes. I have the Heap dump but I can not add images to this post right now.(As my score is less than 10) – Imran Sep 04 '12 at 12:46
  • 1
    Actually the size of a reference is implementation dependant, so in Win64 it would be 8 bytes for instance. I'm not sure why everyone is downvoting this, it seems a valid question to me. – GazTheDestroyer Sep 04 '12 at 12:49
  • @Imran: Now your score is >10 ;-) – BlueM Sep 04 '12 at 12:50
  • @JonHanna they are implemented __based__ on pointers (at least in current versions) but they definitely are references and not pointers which makes a difference when talking about memory consumption – Rune FS Sep 04 '12 at 12:51
  • @BlueM: Thanks, I am gonna upload the image. – Imran Sep 04 '12 at 12:52
  • @RuneFS Yes, but given that he's asking for an explanation of why he's getting results suggesting that that a reference is a different size to a pointer. Still, a 32-bit .NET reference is 32-bits in any case, so the problem is with the experiment. – Jon Hanna Sep 04 '12 at 12:53
  • Perhaps the 12MB contain more than just the list of object references. A display issue with the profiler. – BlueM Sep 04 '12 at 13:02
  • @RuneFS: Do you mean running CLRProfiler is not a right experiment? – Imran Sep 04 '12 at 13:03
  • @BlueM: When I serialized an empty list, the Stream length is just 204 bytes. Even if I ignore this, the memory allocation per a refernced object is near 32 bytes. – Imran Sep 04 '12 at 13:06
  • @Gabe: I have uploaded the image. Could you share your thought? – Imran Sep 04 '12 at 13:08
  • @Imran: Serialization has nothing to do with inmemory representation. – BlueM Sep 04 '12 at 13:12
  • I never said that I simply pointed out that a pointer is not a reference (contrary to somes belief) references are implemented as a special kind of pointer but there plenty of pointers that are no reference – Rune FS Sep 04 '12 at 13:17
  • It's not clear to me that only "pointers" are detailed in these measurements. If you're actually instantiating the reference types, then that would seem to be included with the calculation. – Peter Ritchie Sep 04 '12 at 13:20

3 Answers3

0

There are additional things being stored with the reference (not pointer), such as the Monitor for the C# 'lock' keyword.

akton
  • 14,148
  • 3
  • 43
  • 47
0

Theres overhead to every object. Also you must consider that the CLR does padding from time to time. See Getting the size of a field in bytes with C#

Also a List reserves more memory internally as it currently uses.

Community
  • 1
  • 1
BlueM
  • 6,523
  • 1
  • 25
  • 30
  • I have seen that an empty list consumes just 204 bytes. Memory padding will be done with in a referenced object. I am talking about a client who is just holding the address to an object. In any case the address could not be more than 32 bits on a 32 bit machine. But, why the CLRProfiler is showing 32 bytes instead of 4 bytes? – Imran Sep 04 '12 at 13:11
  • It depends all on whats included in the CLR profilers display. – BlueM Sep 04 '12 at 13:21
  • 1
    Because CLR Profiler includes the cost of referenced objects. Indeed, notice how not just the array is 12MB, but also the list. But the lists's reference to the array is itself only 4bytes. Clearly it's including the 12MB of the array in the size of the list, and likewise the list includes the size of the objects referred to. Otherwise profiler would be useless - it'd just say "you've got about 380000 objects that are each about 30bytes in size, all over the place" without letting you know which containers are responsible for keeping such memory alive in the process. – Jon Hanna Sep 04 '12 at 13:35
  • @JonHanna Thanks much for your clear explanations. Now, it is clear that the 12 MB includes the size of the referenced object also. – Imran Sep 04 '12 at 13:47
  • @JonHanna The answer to my question actually best explained in your [comment](https://stackoverflow.com/questions/12263623/in-c-how-much-memory-would-be-allocated-for-holding-a-pointer-to-a-referenced#comment16444288_12263989). Could you move it to your answer? – Imran Oct 02 '20 at 19:20
0

Try increasing the detail to see if it's including the size of the actual objects referenced.

In comparison, try the following program:

class MemTest
{
    private static object[] TakeUpSpace = new object[1024 * 1024];
    public static void Main(string[] args)
    {
        var arr = TakeUpSpace;//make sure it's instantiated.
        Console.ReadKey(true);//keep running so we can profile.
    }
}

Profiling this on a 32 bit machine shows a 4MB sized array - 4 * 1024 * 1024, but no actual objects referred to.

However this:

class MemTest
{
    private static object[] TakeUpSpace = new object[1024];
    public static void Main(string[] args)
    {
        var arr = TakeUpSpace;//make sure it's instantiated.
        for(var i = 0; i != 1024; ++i)
            arr[i] = new object();
        Console.ReadKey(true);//keep running so we can profile.
    }
}

Shows the array to be 16KB. The object[] itself is 1024 * 4 = 4KB, but each object is at least 3 * pointer-size large (size of fields with a minimum of one pointer-size, plus a header of two pointer-sizes per object).

Requested explanation of header.

Every .NET object obviously contains the fields defined for it. If there are no fields, or the fields are less than the size of a reference, it'll take up that much anyway as a minimum.

Every .NET object contains a syncblock that contains information on whether a lock is held on it, and some other information used for marshalling.

Every .NET object contains a type-handle, from which we can find out which type it is, the implementation of a virtual member, and other type-related information.

As such, when you have an actual object - rather than a null reference, you are guaranteed to be taking up at least 12bytes of memory for the object, along with 4 for the reference to it (there can of course be more than one reference to the same object). You could though be taking up more if the object has more fields or larger fields, and very often will be.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
  • I will do it and would you think having a list than array makes any difference? – Imran Sep 04 '12 at 13:15
  • Not much in itself. Make `TakeUpSpace` a list and set `TakeUpSpace.Capacity = 1024 * 1024` and it'll come in at 4MB. From normal automatic growth, capacity will only get that large if it has contents though, which profiler will include in the size it reports. – Jon Hanna Sep 04 '12 at 13:22
  • Incidentally reducing the "detail" setting on CLR Profiler, will increase how many such objects it shows. Particularly relevant to your case as the size you care about is not just the 4bytes per reference in the lists, internal array but the size (again, minimum 12bytes but could be more) of the objects referred to. – Jon Hanna Sep 04 '12 at 13:31
  • Could you explain bit more about "a header of two pointer-sizes per object"? – Imran Sep 04 '12 at 13:34