Data alignment in Eiffel
- Tags:
- runtime
- performance
- memory
A process access memory in blocks. Thus the base address of data is important. Ideally all data should be aligned to an optimized size of block of memory dependent on different architectures, in order to gain max performance. On some platforms doing this is not only about performance but correctness. On platforms of different architectures, the size of block varies.
Internals
In Eiffel, Eiffel object is stored in a successive block of memory. Each object includes the header and the actual data for attributes. The structure of the header will be shown bellow which is always aligned on different platforms. The runtime allocates memory for each object according to the size of the header and keeps the size of the whole object mutiple of header's size.
Header structure
The header structure above is either 12 bytes and 16 bytes depending on the platform. Most of the time it is 12 bytes when memory alignment is 4 on 32-bit architecture (e.g. x86), but otherwise 16 bytes. Talking about 64-bit, a 0-byte sized object always occupies 32 bytes of memory. Object sizes are therefore 32, 48, 64...
Other Consideration
Based on internals above, keep in mind that each Eiffel object might take larger space than it actually needs for the reason of memory alignment. Normally, one does not have to pay extra attention to data alignment when programming in Eiffel. But in some critical area, especially memory sensitive project that allocates tens of thousands of small objects, some attention to this would help getting most out of it. The basic priciple is that the total size of all attributes in a class should not exceed the border of multiple of the header size when not necessary.
In Eiffel parser, the abstract syntax tree is formed by a lot of small nodes, the size of each nodes is memory sensitive. We keep them as compact as possible. When new attributes are added, some calculation is done to ensure that it does not affect memory usage when not necessary. For example in class {ID_AS}, attributes are:
64bit platform (bytes) | 32bit platform (bytes) | |
index | 4 | 4 |
internal_count | 2 | 2 |
internal_location | 4 | 4 |
name_id | 4 | 4 |
position | 4 | 4 |
Sum | 18 | 18 |
Header size | 16 | 12 |
Object size | 16 * 3 = 48 | 12 * 3 = 36 |
Available | 48 - 16 - 18 = 14 | 36 - 12 - 18 = 6 |
According to the table:
- On 64-bit, we will have 14 bytes available for more data.
- On 32-bit, we will have 6 bytes.
In above example, there are only expanded types. One needs to know that a reference type takes as many as 4 bytes.
Hint:
- In EiffelStudo, Object Internal (Object viewer) reports the physical object size of the viewing object.
Reference
- http://www.ibm.com/developerworks/library/pa-dalign/
- http://msdn.microsoft.com/en-us/library/aa290049(v=vs.71).aspx
- http://software.intel.com/en-us/articles/data-alignment-when-migrating-to-64-bit-intel-architecture