How does aligning memory in a custom double ended stack-based allocator work?
up vote
0
down vote
favorite
I was reading a book about making a game engine because I want to create my own and in the book it suggests writing your own custom allocator so I went off of what the book described and made a double-ended stack-based allocator. The book also mentioned that all allocators should be able to allocate memory aligned. I'm having a little trouble understanding why the book implemented aligning the way they did. In the book there is a function which takes in the size of the amount you want to allocate, and a size for alignment. It says the alignment should only ever be a power of 2 which is where I start to not get it and it also makes sure it can't be greater then 128. My question is why? I have a class called Sprite and sizeof(Sprite) = 136. Let's say that I want to make a struct with one Sprite and an int. What would the alignment be because sizeof(Sprite) is 136 and sizeof(int) is 4. What should I put in alignment for this situation? How do I use this method?
EDIT:
I read Purpose of memory alignment and the answers there didn't help me at all. I understand the purpose of memory alignment and how a 32bit memory should be 4 byte aligned. I also know that 4 byte aligned memory reside on addresses with nibbles at multiples of 4 (ie 0x0, 0x4, 0x8, or 0xC). I just don't understand what happens when I have memory that is 136 bytes (as is the case with my Sprite class) that's in the same struct as a 4 byte int. I also want to know why the method requires alignment to be a power of 2 and less than 128.
Here is the code for aligning:
// Allocate memory in an efficient way which means aligning it
// IMPORTANT: the alignment must be a power of 2 (usually 4 or 16)
void* DESA::allocAligned(size_t size_bytes, size_t alignment, unsigned int flag) {
assert(flag == LEFT | flag == RIGHT);
assert(alignment >= 1);
assert(alignment <= 128);
assert((alignment & (alignment - 1)) == 0); // Make sure it's a power of 2
// Total amount of bytes
size_t expandedSize_bytes = size_bytes + alignment;
// Allocate unaligned memory and convert to uintptr_t
// allocUnaligned just increments a pointer
std::uintptr_t rawAddress;
if (flag == LEFT)
rawAddress = reinterpret_cast<std::uintptr_t>(allocUnaligned(expandedSize_bytes, LEFT));
else if (flag == RIGHT)
rawAddress = reinterpret_cast<std::uintptr_t>(allocUnaligned(expandedSize_bytes, RIGHT));
// Calculate misalignment
size_t mask = alignment - 1;
std::uintptr_t misalignment = rawAddress & mask;
std::ptrdiff_t adjustment = alignment - misalignment;
// Calculate the adjusted address
std::uintptr_t alignedAddress = rawAddress + adjustment;
// Store the adjustment in the byte immediately preceding the adjusted address
assert(adjustment < 256);
U8* pAlignedMem = reinterpret_cast<U8*>(alignedAddress);
pAlignedMem[-1] = static_cast<U8>(adjustment);
return static_cast<void*>(pAlignedMem);
}
c++ memory-management
|
show 1 more comment
up vote
0
down vote
favorite
I was reading a book about making a game engine because I want to create my own and in the book it suggests writing your own custom allocator so I went off of what the book described and made a double-ended stack-based allocator. The book also mentioned that all allocators should be able to allocate memory aligned. I'm having a little trouble understanding why the book implemented aligning the way they did. In the book there is a function which takes in the size of the amount you want to allocate, and a size for alignment. It says the alignment should only ever be a power of 2 which is where I start to not get it and it also makes sure it can't be greater then 128. My question is why? I have a class called Sprite and sizeof(Sprite) = 136. Let's say that I want to make a struct with one Sprite and an int. What would the alignment be because sizeof(Sprite) is 136 and sizeof(int) is 4. What should I put in alignment for this situation? How do I use this method?
EDIT:
I read Purpose of memory alignment and the answers there didn't help me at all. I understand the purpose of memory alignment and how a 32bit memory should be 4 byte aligned. I also know that 4 byte aligned memory reside on addresses with nibbles at multiples of 4 (ie 0x0, 0x4, 0x8, or 0xC). I just don't understand what happens when I have memory that is 136 bytes (as is the case with my Sprite class) that's in the same struct as a 4 byte int. I also want to know why the method requires alignment to be a power of 2 and less than 128.
Here is the code for aligning:
// Allocate memory in an efficient way which means aligning it
// IMPORTANT: the alignment must be a power of 2 (usually 4 or 16)
void* DESA::allocAligned(size_t size_bytes, size_t alignment, unsigned int flag) {
assert(flag == LEFT | flag == RIGHT);
assert(alignment >= 1);
assert(alignment <= 128);
assert((alignment & (alignment - 1)) == 0); // Make sure it's a power of 2
// Total amount of bytes
size_t expandedSize_bytes = size_bytes + alignment;
// Allocate unaligned memory and convert to uintptr_t
// allocUnaligned just increments a pointer
std::uintptr_t rawAddress;
if (flag == LEFT)
rawAddress = reinterpret_cast<std::uintptr_t>(allocUnaligned(expandedSize_bytes, LEFT));
else if (flag == RIGHT)
rawAddress = reinterpret_cast<std::uintptr_t>(allocUnaligned(expandedSize_bytes, RIGHT));
// Calculate misalignment
size_t mask = alignment - 1;
std::uintptr_t misalignment = rawAddress & mask;
std::ptrdiff_t adjustment = alignment - misalignment;
// Calculate the adjusted address
std::uintptr_t alignedAddress = rawAddress + adjustment;
// Store the adjustment in the byte immediately preceding the adjusted address
assert(adjustment < 256);
U8* pAlignedMem = reinterpret_cast<U8*>(alignedAddress);
pAlignedMem[-1] = static_cast<U8>(adjustment);
return static_cast<void*>(pAlignedMem);
}
c++ memory-management
Possible duplicate of Purpose of memory alignment
– user10605163
Nov 20 at 4:21
Im sorry if I did actually just ask the same question but I did read that post and it just made me more confused. All I really want to know is how am I supposed to use the method above and why are the parameters what they are
– Artur S.
Nov 20 at 4:24
As forallocate 4 byte integer next to it
, an allocator generally makes no guarantee how multiple allocations are ordered in memory. To allocate a 4 bytes for an integer you just pass4
assize_bytes
. Same for a struct, passsizeof(Sprite)
tosize_bytes
. As for alignment, there are some minimum alignments requirements on types in c++, see thealignof
operator. Everything above that is usually done for performance reasons. I don't think you should start with a custom allocator. You will need to understand memory layout and management to make good use of it.
– user10605163
Nov 20 at 4:33
Thank you. I really appreciate your comment. I know I probably shouldn't start with a custom allocator. I probably won't have a lot of uses for it anyway Im sure my code will run fine with new/delete heap allocation however I know most efficient game engines use custom allocators and I would really love to learn about them. I will try to look into memory layout and management a lot more. Would you by any chance know of any good sources if you don't mind me asking.
– Artur S.
Nov 20 at 4:38
Honestly I don't really know much either and can't provide you with a reference. I suppose your questions are answerable, though you should make clearer what you mean with theSprite
andint
example. Are you talking about allocating aSprite
and anint
independently or allocating onestruct { Sprite sprite; int i; }
?
– user10605163
Nov 20 at 5:10
|
show 1 more comment
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I was reading a book about making a game engine because I want to create my own and in the book it suggests writing your own custom allocator so I went off of what the book described and made a double-ended stack-based allocator. The book also mentioned that all allocators should be able to allocate memory aligned. I'm having a little trouble understanding why the book implemented aligning the way they did. In the book there is a function which takes in the size of the amount you want to allocate, and a size for alignment. It says the alignment should only ever be a power of 2 which is where I start to not get it and it also makes sure it can't be greater then 128. My question is why? I have a class called Sprite and sizeof(Sprite) = 136. Let's say that I want to make a struct with one Sprite and an int. What would the alignment be because sizeof(Sprite) is 136 and sizeof(int) is 4. What should I put in alignment for this situation? How do I use this method?
EDIT:
I read Purpose of memory alignment and the answers there didn't help me at all. I understand the purpose of memory alignment and how a 32bit memory should be 4 byte aligned. I also know that 4 byte aligned memory reside on addresses with nibbles at multiples of 4 (ie 0x0, 0x4, 0x8, or 0xC). I just don't understand what happens when I have memory that is 136 bytes (as is the case with my Sprite class) that's in the same struct as a 4 byte int. I also want to know why the method requires alignment to be a power of 2 and less than 128.
Here is the code for aligning:
// Allocate memory in an efficient way which means aligning it
// IMPORTANT: the alignment must be a power of 2 (usually 4 or 16)
void* DESA::allocAligned(size_t size_bytes, size_t alignment, unsigned int flag) {
assert(flag == LEFT | flag == RIGHT);
assert(alignment >= 1);
assert(alignment <= 128);
assert((alignment & (alignment - 1)) == 0); // Make sure it's a power of 2
// Total amount of bytes
size_t expandedSize_bytes = size_bytes + alignment;
// Allocate unaligned memory and convert to uintptr_t
// allocUnaligned just increments a pointer
std::uintptr_t rawAddress;
if (flag == LEFT)
rawAddress = reinterpret_cast<std::uintptr_t>(allocUnaligned(expandedSize_bytes, LEFT));
else if (flag == RIGHT)
rawAddress = reinterpret_cast<std::uintptr_t>(allocUnaligned(expandedSize_bytes, RIGHT));
// Calculate misalignment
size_t mask = alignment - 1;
std::uintptr_t misalignment = rawAddress & mask;
std::ptrdiff_t adjustment = alignment - misalignment;
// Calculate the adjusted address
std::uintptr_t alignedAddress = rawAddress + adjustment;
// Store the adjustment in the byte immediately preceding the adjusted address
assert(adjustment < 256);
U8* pAlignedMem = reinterpret_cast<U8*>(alignedAddress);
pAlignedMem[-1] = static_cast<U8>(adjustment);
return static_cast<void*>(pAlignedMem);
}
c++ memory-management
I was reading a book about making a game engine because I want to create my own and in the book it suggests writing your own custom allocator so I went off of what the book described and made a double-ended stack-based allocator. The book also mentioned that all allocators should be able to allocate memory aligned. I'm having a little trouble understanding why the book implemented aligning the way they did. In the book there is a function which takes in the size of the amount you want to allocate, and a size for alignment. It says the alignment should only ever be a power of 2 which is where I start to not get it and it also makes sure it can't be greater then 128. My question is why? I have a class called Sprite and sizeof(Sprite) = 136. Let's say that I want to make a struct with one Sprite and an int. What would the alignment be because sizeof(Sprite) is 136 and sizeof(int) is 4. What should I put in alignment for this situation? How do I use this method?
EDIT:
I read Purpose of memory alignment and the answers there didn't help me at all. I understand the purpose of memory alignment and how a 32bit memory should be 4 byte aligned. I also know that 4 byte aligned memory reside on addresses with nibbles at multiples of 4 (ie 0x0, 0x4, 0x8, or 0xC). I just don't understand what happens when I have memory that is 136 bytes (as is the case with my Sprite class) that's in the same struct as a 4 byte int. I also want to know why the method requires alignment to be a power of 2 and less than 128.
Here is the code for aligning:
// Allocate memory in an efficient way which means aligning it
// IMPORTANT: the alignment must be a power of 2 (usually 4 or 16)
void* DESA::allocAligned(size_t size_bytes, size_t alignment, unsigned int flag) {
assert(flag == LEFT | flag == RIGHT);
assert(alignment >= 1);
assert(alignment <= 128);
assert((alignment & (alignment - 1)) == 0); // Make sure it's a power of 2
// Total amount of bytes
size_t expandedSize_bytes = size_bytes + alignment;
// Allocate unaligned memory and convert to uintptr_t
// allocUnaligned just increments a pointer
std::uintptr_t rawAddress;
if (flag == LEFT)
rawAddress = reinterpret_cast<std::uintptr_t>(allocUnaligned(expandedSize_bytes, LEFT));
else if (flag == RIGHT)
rawAddress = reinterpret_cast<std::uintptr_t>(allocUnaligned(expandedSize_bytes, RIGHT));
// Calculate misalignment
size_t mask = alignment - 1;
std::uintptr_t misalignment = rawAddress & mask;
std::ptrdiff_t adjustment = alignment - misalignment;
// Calculate the adjusted address
std::uintptr_t alignedAddress = rawAddress + adjustment;
// Store the adjustment in the byte immediately preceding the adjusted address
assert(adjustment < 256);
U8* pAlignedMem = reinterpret_cast<U8*>(alignedAddress);
pAlignedMem[-1] = static_cast<U8>(adjustment);
return static_cast<void*>(pAlignedMem);
}
c++ memory-management
c++ memory-management
edited Nov 20 at 5:20
asked Nov 20 at 4:16
Artur S.
34
34
Possible duplicate of Purpose of memory alignment
– user10605163
Nov 20 at 4:21
Im sorry if I did actually just ask the same question but I did read that post and it just made me more confused. All I really want to know is how am I supposed to use the method above and why are the parameters what they are
– Artur S.
Nov 20 at 4:24
As forallocate 4 byte integer next to it
, an allocator generally makes no guarantee how multiple allocations are ordered in memory. To allocate a 4 bytes for an integer you just pass4
assize_bytes
. Same for a struct, passsizeof(Sprite)
tosize_bytes
. As for alignment, there are some minimum alignments requirements on types in c++, see thealignof
operator. Everything above that is usually done for performance reasons. I don't think you should start with a custom allocator. You will need to understand memory layout and management to make good use of it.
– user10605163
Nov 20 at 4:33
Thank you. I really appreciate your comment. I know I probably shouldn't start with a custom allocator. I probably won't have a lot of uses for it anyway Im sure my code will run fine with new/delete heap allocation however I know most efficient game engines use custom allocators and I would really love to learn about them. I will try to look into memory layout and management a lot more. Would you by any chance know of any good sources if you don't mind me asking.
– Artur S.
Nov 20 at 4:38
Honestly I don't really know much either and can't provide you with a reference. I suppose your questions are answerable, though you should make clearer what you mean with theSprite
andint
example. Are you talking about allocating aSprite
and anint
independently or allocating onestruct { Sprite sprite; int i; }
?
– user10605163
Nov 20 at 5:10
|
show 1 more comment
Possible duplicate of Purpose of memory alignment
– user10605163
Nov 20 at 4:21
Im sorry if I did actually just ask the same question but I did read that post and it just made me more confused. All I really want to know is how am I supposed to use the method above and why are the parameters what they are
– Artur S.
Nov 20 at 4:24
As forallocate 4 byte integer next to it
, an allocator generally makes no guarantee how multiple allocations are ordered in memory. To allocate a 4 bytes for an integer you just pass4
assize_bytes
. Same for a struct, passsizeof(Sprite)
tosize_bytes
. As for alignment, there are some minimum alignments requirements on types in c++, see thealignof
operator. Everything above that is usually done for performance reasons. I don't think you should start with a custom allocator. You will need to understand memory layout and management to make good use of it.
– user10605163
Nov 20 at 4:33
Thank you. I really appreciate your comment. I know I probably shouldn't start with a custom allocator. I probably won't have a lot of uses for it anyway Im sure my code will run fine with new/delete heap allocation however I know most efficient game engines use custom allocators and I would really love to learn about them. I will try to look into memory layout and management a lot more. Would you by any chance know of any good sources if you don't mind me asking.
– Artur S.
Nov 20 at 4:38
Honestly I don't really know much either and can't provide you with a reference. I suppose your questions are answerable, though you should make clearer what you mean with theSprite
andint
example. Are you talking about allocating aSprite
and anint
independently or allocating onestruct { Sprite sprite; int i; }
?
– user10605163
Nov 20 at 5:10
Possible duplicate of Purpose of memory alignment
– user10605163
Nov 20 at 4:21
Possible duplicate of Purpose of memory alignment
– user10605163
Nov 20 at 4:21
Im sorry if I did actually just ask the same question but I did read that post and it just made me more confused. All I really want to know is how am I supposed to use the method above and why are the parameters what they are
– Artur S.
Nov 20 at 4:24
Im sorry if I did actually just ask the same question but I did read that post and it just made me more confused. All I really want to know is how am I supposed to use the method above and why are the parameters what they are
– Artur S.
Nov 20 at 4:24
As for
allocate 4 byte integer next to it
, an allocator generally makes no guarantee how multiple allocations are ordered in memory. To allocate a 4 bytes for an integer you just pass 4
as size_bytes
. Same for a struct, pass sizeof(Sprite)
to size_bytes
. As for alignment, there are some minimum alignments requirements on types in c++, see the alignof
operator. Everything above that is usually done for performance reasons. I don't think you should start with a custom allocator. You will need to understand memory layout and management to make good use of it.– user10605163
Nov 20 at 4:33
As for
allocate 4 byte integer next to it
, an allocator generally makes no guarantee how multiple allocations are ordered in memory. To allocate a 4 bytes for an integer you just pass 4
as size_bytes
. Same for a struct, pass sizeof(Sprite)
to size_bytes
. As for alignment, there are some minimum alignments requirements on types in c++, see the alignof
operator. Everything above that is usually done for performance reasons. I don't think you should start with a custom allocator. You will need to understand memory layout and management to make good use of it.– user10605163
Nov 20 at 4:33
Thank you. I really appreciate your comment. I know I probably shouldn't start with a custom allocator. I probably won't have a lot of uses for it anyway Im sure my code will run fine with new/delete heap allocation however I know most efficient game engines use custom allocators and I would really love to learn about them. I will try to look into memory layout and management a lot more. Would you by any chance know of any good sources if you don't mind me asking.
– Artur S.
Nov 20 at 4:38
Thank you. I really appreciate your comment. I know I probably shouldn't start with a custom allocator. I probably won't have a lot of uses for it anyway Im sure my code will run fine with new/delete heap allocation however I know most efficient game engines use custom allocators and I would really love to learn about them. I will try to look into memory layout and management a lot more. Would you by any chance know of any good sources if you don't mind me asking.
– Artur S.
Nov 20 at 4:38
Honestly I don't really know much either and can't provide you with a reference. I suppose your questions are answerable, though you should make clearer what you mean with the
Sprite
and int
example. Are you talking about allocating a Sprite
and an int
independently or allocating one struct { Sprite sprite; int i; }
?– user10605163
Nov 20 at 5:10
Honestly I don't really know much either and can't provide you with a reference. I suppose your questions are answerable, though you should make clearer what you mean with the
Sprite
and int
example. Are you talking about allocating a Sprite
and an int
independently or allocating one struct { Sprite sprite; int i; }
?– user10605163
Nov 20 at 5:10
|
show 1 more comment
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53386137%2fhow-does-aligning-memory-in-a-custom-double-ended-stack-based-allocator-work%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Possible duplicate of Purpose of memory alignment
– user10605163
Nov 20 at 4:21
Im sorry if I did actually just ask the same question but I did read that post and it just made me more confused. All I really want to know is how am I supposed to use the method above and why are the parameters what they are
– Artur S.
Nov 20 at 4:24
As for
allocate 4 byte integer next to it
, an allocator generally makes no guarantee how multiple allocations are ordered in memory. To allocate a 4 bytes for an integer you just pass4
assize_bytes
. Same for a struct, passsizeof(Sprite)
tosize_bytes
. As for alignment, there are some minimum alignments requirements on types in c++, see thealignof
operator. Everything above that is usually done for performance reasons. I don't think you should start with a custom allocator. You will need to understand memory layout and management to make good use of it.– user10605163
Nov 20 at 4:33
Thank you. I really appreciate your comment. I know I probably shouldn't start with a custom allocator. I probably won't have a lot of uses for it anyway Im sure my code will run fine with new/delete heap allocation however I know most efficient game engines use custom allocators and I would really love to learn about them. I will try to look into memory layout and management a lot more. Would you by any chance know of any good sources if you don't mind me asking.
– Artur S.
Nov 20 at 4:38
Honestly I don't really know much either and can't provide you with a reference. I suppose your questions are answerable, though you should make clearer what you mean with the
Sprite
andint
example. Are you talking about allocating aSprite
and anint
independently or allocating onestruct { Sprite sprite; int i; }
?– user10605163
Nov 20 at 5:10