size of, and how does it add up@@

Typically, the per-object overhead is 8 bytes on 32-bit, and 12-byte on a 64-bit machine, as shown on, but sometimes rounded to 16 bytes.

(Hypotheses and Personal opinion only. I’m no authority.)

Minimum info to be stored in an instance —

– (4-byte) wait-set as a hidden field — to hold the waiting threads. Expandable set, so perhaps a WS_pointer to a linked list
** It’s probably inefficient to try to “save” memory by building a static VM-wide lookup table of {instance-address, wait-set}. As this table grows, such hashtable lookup is going to impact the most time-critical operations in JVM. Not having this lookup means minimum overhead locating the wait-set.
** this particular WS_pointer starts out as null pointer
** Note c# value types don’t have wait-set. c# Reference types do. The sync-block takes 4-bytes
** why linked list? Well, Arrays can’t grow. Vector involves re-allocation.

– How about the data structure holding the set of threads blocked in lock() or synchronized keyword? A mutex “contender set” associated with each instance? Apparently there’s no such thing mentioned in popular literature. Is it possible to put these contenders in the wait-set but use a flag to distinguish?

– (4-byte) vptr as a hidden field — If you try to be clever and put this ptr as the first element of the wait-set, then every Object instance still must occupy 64bits == WS_pointer + 1st element in the wait set. Therefore it’s faster to store the vptr directly in the Object instance. Note the vtable also holds the runtime type info, just as in c++ RTTI. Vtable can even hold a pointer to the “class” object.

– ? pointer to the class object as a hidden (static) field — representing the Runtime type of the object.
** This can be stored in the per-class vtbl, as C++ does. This hidden field occupies 32 bits per Class, not per instance.
** I believe myObject.getClass() would use this pointer.
** See my blog post on type info stored inside instances (

– hashcode — Once generated, hashcode must not mutate (due to garbage collection relocation), until object state changes.
** I feel this can live on the wait-set, since most Object instances don’t get a hashcode generated.
** Why not use another hidden field? Well, that would require 32 bits dedicated real estate per object, even if an object needs no hashcode in its lifetime.
** Note python hashcode never mutates. See separate blog post.

?? this-pointer as a hidden field — to hold “my” own address. Remember this.m(…) is compiled to m(this, …) to let m() access fields of the host object.
** However, I believe this-pointer is possibly added (as a hidden field) only when you subclass and introduce a field, and then a method referencing that field. There’s no need to add this-pointer to classes whose instance methods never access instance fields. Such an object doesn’t (need to) know it’s own address — like a lost child.
** even in those “other” cases, I feel it’s possible for the compiler to remove this-pointer as a field (reducing memory footprint) because compilers implicitly translate myInstance.m1() to m1(&myIntance)

In conclusion, I’d guess minimum size = 8 bytes but will grow when hashcode generated.

Q1a: min size of a c# struct or any value type instance?
%%A: C# structs need zero overhead, so an Int32 instance needs just 32 bits.
When we call myStruct.m2(), there’s no vptr involved — just a compile-time resolved function call as in C and non-OO languages. Compiler translates it to some_Free_Function(ptr_to_myStruct). Note even for this value-type there’s no pass-by-value — no passing at all. Just translation by compiler.

Q1b: min size of c# System.Object instance.
A: Supposed to be 8 bytes minimum (A value type instance has no such overhead)
* 4-byte vptr
* 4-byte sync block
A real instance seem to be 12-bytes long.

Q2: why is the minimum size of an empty c++ object no more than 1 byte?
%%A: obvious from the analysis above.

Q2b: why not 0 byte?
A: an object is defined as a storage location. Even if there’s no field in it, a=new MyObject() and b=new MyObject() (twice in a row, single-threaded program) must produce 2 objects at 2 locations.

Note the size of an empty c++ string class instance is 12 bytes, according to [[c++ primer]]

According to P89 [[C# in depth]] a C# byte takes 1 byte, but 8+1 bytes of heap usage when “boxed”. These 9 bytes are rounded up to 12 bytes (memory alignment). Since heap objects are nameless and accessed only via a pointer, the pointer becomes a field (of the boxed object) and takes 4 bytes (assuming a 32-bit machine)


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s