我正在阅读Game Engine Architecture by Jason Gregory S.212,当我偶然发现他正在分配对齐内存的代码时。我认为他正在制造内存损坏,我自己尝试使用以下代码:
void* myalloc( unsigned size )
{
// this will not return a valid memory address but its ok since
// it will never be dereferenced! its just to check what if a real malloc would
// return this obviously UNALIGNED memory address
return reinterpret_cast<void*>( 0x00001 );
}
void* allocatedAligned( unsigned size_bytes, unsigned alignment )
{
unsigned expandedSize_bytes = size_bytes + alignment;
unsigned rawAddress = (unsigned)myalloc( expandedSize_bytes );
unsigned mask = alignment - 1;
unsigned misalignment = rawAddress & mask;
unsigned adjustment = alignment - misalignment;
unsigned alignedAddress = rawAddress + adjustment;
unsigned* ptrAdjustment = reinterpret_cast<unsigned*>( alignedAddress - 4 );
//*ptrAdjustment = adjustment; //Corruption here
//return reinterpret_cast<unsigned*>( alignedAddress ); this is what jasons function normally returns
return ptrAdjustment;
}
int main()
{
void* ptr = allocatedAligned( 4, 4 );
std::cout << ptr << std::endl; // this shouldn't print an address lower than 0x0001
return 1;
}
对齐的工作原理应该如此,但我必须对行*ptrAdjustment = adjustment
,因为它会破坏内存。它在从myalloc()收到的地址之前写入内存,还是我错了?
main()
不应该打印任何小于myalloc()返回的地址?!
我期待着你的回答,谢谢!
注意:这个例子是关于:写入内存的位置,而不是:myalloc()
返回错误的内存....
(我对代码的更改:
U32
myalloc()
代替allocateUnaligned()
答案 0 :(得分:2)
代码被破坏了。如果malloc将返回已经正确对齐的地址,比如0并且您请求8字节对齐的地址,则代码将返回地址4,这显然是错误的。应删除以下行:
unsigned* ptrAdjustment = reinterpret_cast<unsigned*>( alignedAddress - 4 );
代码应该只返回alignedAddress:
return reinterpret_cast<unsigned*>( alignedAddress );
(也应该是void*
而不是unsigned*
,他应该使用size_t
而不是unsigned
)。如果您希望代码返回原始的malloc()地址,以防它已经正确对齐,您只需将上面的行更改为:
return reinterpret_cast<void*>(misalignment?alignedAddress:rawAddress);
同样要迂腐,应该在函数中断言以验证对齐是2的幂,例如assert((alignment&(alignment-1))==0);
答案 1 :(得分:1)
完成示例的计算:
size_bytes
为4,unsigned alignment
为4
expandedSize_bytes
设置为8
mask
设置为3
misalignment
设置为1&amp; 3是1。
adjustment
设置为4 - 1,即3。
alignedAddress
设置为0x0001 + 3,即4。
ptrAdjustment
设置为4 - 4,即0x0000。
所以是的,如果您的示例场景确实发生了,那注释掉的行会尝试写入分配区域之外的内存。
另一方面,如果原始地址已经对齐至少4并且请求的对齐为4或更大,那么看起来数学计算结果是没有无效的内存访问。也许作者认为会是这种情况。或许也许他只针对那种场景测试了他的数学。毕竟,使用现代C / C ++ malloc本身应该只返回具有合理对齐的地址。
答案 2 :(得分:0)
我没有读过你提到的这本书和这种特殊的技巧。但我认为有一些基本概念需要提及来回答你的问题。
但我必须反对行* ptrAdjustment =调整,因为它恕我直言 腐蚀记忆
这不是内存损坏的示例,因为上面的程序不在示例代码中分配内存。上面的程序在
行崩溃了*ptrAdjustment = adjustment;
因为 ptrAdjustment 指针没有从堆内存分配器接收的有效内存(NULL指针)。因为在上面的代码中我们没有分配任何内存。
我认为我们需要更改上面的代码以从malloc()API分配地址。这样 myalloc 将返回有效内存。
void* myalloc( unsigned size )
{
return reinterpret_cast<void*>( malloc(size) );
}
然而,我们不应该打扰(直到绝对需要)很多关于地址的对齐,因为内存分配器会返回正确对齐的地址(8或16字节)。
此外,您的程序必须编写 myfree() 类型的函数来释放由 myalloc()分配的内存即可。这与内存损坏同样严重。
在C ++程序中,我们应该避免使用原始指针,而是开始使用STL container和smart pointer。