C++ - 对齐内存

Cha*_*one 4 c++ memory-alignment

我真的很想了解这两行发生了什么

const int PAGES = 8 * 1024;

// PAGES + extra 4KiB for alignment
uint8_t * mem = new uint8_t [ PAGES * CCPU::PAGE_SIZE + CCPU::PAGE_SIZE ];

// align to a mutiple of 4KiB
uint8_t * memAligned = (uint8_t *) (( ((uintptr_t) mem) + CCPU::PAGE_SIZE - 1) & ~(uintptr_t) ~CCPU::ADDR_MASK );
Run Code Online (Sandbox Code Playgroud)

特别是最后一行,我什么都不懂......

Sha*_*ger 6

它正在分配一个指向页面对齐内存块的指针,即PAGES使用C++分配器而不是更多OS特定的专用对齐分配函数(例如POSIX posix_memalign或C11aligned_alloc)的页面数.

首先,它分配PAGES + 1内存页面(可能是或不是页面对齐),然后它向前调整结果指针,使其指向结果中的第一页对齐字节.通过分配额外的页面,它知道它肯定会有足够大的分配来使PAGES超出该点的可用页面.该方案只需要确保它deleteš mem当它这样做,而不是memAligned(删除后可能会无论是程序崩溃了,后来由于堆损坏,或者只是内存泄漏,它是不确定的行为,所以融化你的电脑去渣是一种法律行为).

最后一行在数值上相当于向上舍入到页面大小的下一个倍数; 它增加了PAGE_SIZE - 1指针(所以如果指针已经指向页对齐,它仍然在同一个页面,否则它移动到下一个页面),然后面具关地址的低位(其撤销在"已经页面加入对齐的"case",在所有其他情况下,将指针重置为未对齐指针后的第一页的开头mem.

细节:~是按位反转,因此ADDR_MASK,这可能类似于0x00000FFF4096字节页,变为0xFFFFF000(翻转所有位).当&-ing一个值时,只保留两个操作数中设置的位.举个例子:对于一个32位指针,我们假设new给了我们0xDEADBEEF,并且PAGE_SIZE是4096.添加4095(0xFFF)意味着我们有'0xDEADCEEE'.然后我们屏蔽0xFFFFF000,这消除了低位,给我们0xDEADC000,第一页对齐的地址跟随0xDEADBEEF.返回的任何非页面对齐的地址都会发生同样的事情new.

如果该值已经页面虽然一致,比如说0xDEADB000,增加对4095/0xFFF让我们动0xDEADBFFF(请注意如何在没有位0xDEADB改变),所以当我们掩模以取得一致的地址,我们回来0xDEADB000再次,既然我们已经页对齐.

强制转换uintptr_t是为了确保我们可以使用数学运算符操作地址,并确保按位反转填充匹配指针所需的所有位(如果它的大小不合适,则可能会反转,然后上转换,突然间你会有左边的一堆零,而不仅仅是右边的,你最终会掩盖指针中的重要位,所以它指向一个完全不同的错误位置).