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);
}









share|improve this question
























  • 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 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












  • 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















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);
}









share|improve this question
























  • 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 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












  • 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













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);
}









share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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












  • 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


















  • 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 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












  • 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
















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

















active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















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






























active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes
















draft saved

draft discarded




















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

Wiesbaden

Marschland

Dieringhausen