Skip to main content
gamedev.net
🔒 Locked

Memory Alignment

Started by cilcoder 5 replies 750+ views
Original Post
cilcoder
cilcoder
I''m working on an operating system as a project to learn more about how a kernel and low-level code works. I''m getting ready to implement malloc/new/new[] and free/delete/delete[], etc... I''ve read some things about malloc that refer to it allocating memory aligned for any use. Can someone tell me more about proper alignment for memory on different architectures and the different restrictions they have? I think I understand what they mean by alignment but just to be sure, when a block of memory is 4Byte/DWORD aligned that means that it''s starting address is divisible by 4 correct? Thanks for the help guys(and girls).
SiCrane
SiCrane
4 byte alignment means the memory address is a multiple of 4 bytes. DWORD alignment generally means the memory address is a multiple of twice the word size. This isn''t the case on most Windows systems, where a DWORD is actually the length of a single word.

In any case, proper alignment in the return value for malloc() for most 32 bit processors is actually 8 bytes, due to the fact that malloc()''s return value should be properly aligned for any primitive C type, and the proper alignment for a double is generally at 8 bytes.
cilcoder
cilcoder
quote:
In any case, proper alignment in the return value for malloc() for most 32 bit processors is actually 8 bytes, due to the fact that malloc()''s return value should be properly aligned for any primitive C type, and the proper alignment for a double is generally at 8 bytes.


That''s my question. What do you mean properly aligned for any primitive C type? Why is the proper alignment for a double generally 8 bytes? Why does it matter as long as malloc returns an address to however much free memory was requested?

* Tries to understand
Namethatnobodyelsetook
Namethatnobodyelsetook
Some processors (old 68000s for example) couldn''t use any address. They required memory addresses to be even, unless you were accessing a byte.

Most processors incur some sort of fetch penalty if the data access crosses a bus size boundary (fetching 4 bytes at address 6 would require hardware to fetch a DWORD at 4, a DWORD at 8, and then mix the appropriate parts together).

Typically every part of the CPU works at some power of two multiple of bus width, and typically a C compiler for a platform defines it''s types as some power of two multiple of bus width.

Malloc *could* have been specified to return a multiple of bus width, and would have been fine... guaranteed accessable, and fairly quick access. Instead it''s defined to return a multiple of the C compilers largest data type. On All x86 compilers this happens to be "double" and "long long", both of which are 8 bytes. This helps you create datatypes that don''t cross other magic boundaries, such as cache line size, or memory page size.

Lets make an example...

Your cache width is 128 bytes
Your memory page width is 4096 bytes
Malloc is aligned just to bus width of 32 bits, not datatype size of 64 bits.
Alloc space for double (or array of doubles).
Returned address is 1020.
Accessing this double lands in two cache pages AND two memory pages

If you enforce alignment to the largest type, an array of those objects will never contain an element that crosses any odd boundaries.

You can still create bad alignment situations like this if you pay no attention to your structure and class organization, but you CAN attempt to control it. Basic types are always fine with malloc''s rule in place.
Jan Wassenberg
Jan Wassenberg
Memory controllers generally cannot access unaligned data - it may be split up between 2 separate pages, and therefore cannot be read in one operation. You can avoid this by naturally aligning everything, i.e. choose variable_address = 0 (mod 2 ^ ceil(log2(variable_size))). Some processors (notably x86) go to the trouble of splitting unaligned reads into 2 transfers, which is much slower, but it works; more RISC-style designs usually flat-out refuse unaligned accesses.
E8 17 00 42 CE DC D2 DC E4 EA C4 40 CA DA C2 D8 CC 40 CA D0 E8 40E0 CA CA 96 5B B0 16 50 D7 D4 02 B2 02 86 E2 CD 21 58 48 79 F2 C3
SiCrane
SiCrane
quote:
Original post by Namethatnobodyelsetook
Malloc *could* have been specified to return a multiple of bus width, and would have been fine... guaranteed accessable, and fairly quick access. Instead it''s defined to return a multiple of the C compilers largest data type.


No, it''s defined as: "The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly freed or reallocated)."

On some platforms this may mean that it returns a multiple of the size of the largest primitive type. On some platforms this may only mean a multiple of the bus width. On other platforms this may mean jack squat. For some processors you could perform no alignment treatment and still be standards compliant, but just darn slow. In practice that doesn''t happen on commercial compilers. (Unless you severely mess with build flags.)
cilcoder
cilcoder
Thanks a lot(all of you). I think I understands things a bit better now.

-Philip

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.