Tuesday, February 19, 2008

Memory layout (and size) of a object

After reading a article about memory layout of objects in Delphi i was curious about how fpc behaves. So i did some small tests:

Memory layout of objects (instances of a class)

At offset 0 resides the virtual method table. Starting from ofsset 4 comes the fields. Just like in Delphi.

Number of associated methods

The number of associated methods and if they are virtual does not influence the object size. Just like in Delphi.

Type of the fields

According to the cited article, Delphi reserves 4 bytes for each field even if the type has a size of 1 byte. Here comes the fun.

Take the following classes:

TOneFlagClass = class
Flag1: Boolean;

TTwoFlagClass = class
Flag1: Boolean;
Flag2: Boolean;

The size of TOneFlagClass and TTwoFlagClass are 5 and 6 bytes respectively (4 for the vmt and 1 for each field). The memory offsets of Flag1 and Flag2 are 4 and 5.

Delphi is a bit different here. The size of both classes are 8. The memory offsets of the fields are the same as fpc.

At this time i think: "In this case is better to place less than 4 bytes fields at the end of the class declaration to avoid subsequent fields to be accessed outside the dword boundary"

I was wrong. In fact half wrong:

Take the following classes:
TFlagFirstClass = class
Flag1: Boolean;
Int1: Integer;

TFlagLastClass = class
Int1: Integer;
Flag1: Boolean;
The size of TFlagFirstClass and TFlagLastClass are 12 and 9 respectively. The compiler allocates 4 bytes for the boolean field to maintain subsequent fields (that has a size of 4 bytes) aligned with the dword boundary.

If another boolean field (Flag2) is added just after Flag1, the instance size is not affected. In fact, grouping 4 boolean (or another 1 byte type) fields together will lead to the same instance size as only one boolean field if those are succeeded by Integer or Pointer like types.

In the end, my suggestion is still valid: put the "less than 4 bytes field types" at the end of the field declaration of the class (or group together in groups with 4 bytes in total). You will save some memory.

If you are not convinced compare size of a class with the following fields sequence:
Boolean, Integer, Boolean, Integer, Boolean, Integer, Boolean, Integer
Boolean, Boolean, Boolean, Boolean, Integer, Integer, Integer, Integer
Integer, Integer, Integer, Integer, Boolean, Boolean, Boolean, Boolean

Some notes:
  • Object here is not referenced as the object type (that has the same memory layout of a record), but as the instance of a class
  • There's no difference between mode delphi and objfpc
  • It's valid only for i386 architeture. No idea how this works in ppc, amd64, arm


Jose Alfredo Be said...

Hi Luiz Americo,you ask permission to publish the tutorials that you have written to the Spanish first what you see in http://cacharreandoando.blogspot.com/

Luiz Américo said...

No problem, keep doing.

Anonymous said...

This is much like so called "C alignment", iow fields with size "X" are allocated on size "x" borders.

It shouldn't matter btw if booleans are first or last, as long as they are grouped.