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)
特别是最后一行,我什么都不懂......
它正在分配一个指向页面对齐内存块的指针,即PAGES
使用C++分配器而不是更多OS特定的专用对齐分配函数(例如POSIX posix_memalign
或C11aligned_alloc
)的页面数.
首先,它分配PAGES + 1
内存页面(可能是或不是页面对齐),然后它向前调整结果指针,使其指向结果中的第一页对齐字节.通过分配额外的页面,它知道它肯定会有足够大的分配来使PAGES
超出该点的可用页面.该方案只需要确保它delete
š mem
当它这样做,而不是memAligned
(删除后可能会无论是程序崩溃了,后来由于堆损坏,或者只是内存泄漏,它是不确定的行为,所以融化你的电脑去渣是一种法律行为).
最后一行在数值上相当于向上舍入到页面大小的下一个倍数; 它增加了PAGE_SIZE - 1
指针(所以如果指针已经指向页对齐,它仍然在同一个页面,否则它移动到下一个页面),然后面具关地址的低位(其撤销在"已经页面加入对齐的"case",在所有其他情况下,将指针重置为未对齐指针后的第一页的开头mem
.
细节:~
是按位反转,因此ADDR_MASK
,这可能类似于0x00000FFF
4096字节页,变为0xFFFFF000
(翻转所有位).当&
-ing一个值时,只保留两个操作数中设置的位.举个例子:对于一个32位指针,我们假设new
给了我们0xDEADBEEF
,并且PAGE_SIZE
是4096.添加4095(0xFFF
)意味着我们有'0xDEADCEEE'.然后我们屏蔽0xFFFFF000
,这消除了低位,给我们0xDEADC000
,第一页对齐的地址跟随0xDEADBEEF
.返回的任何非页面对齐的地址都会发生同样的事情new
.
如果该值已经页面虽然一致,比如说0xDEADB000
,增加对4095/0xFFF
让我们动0xDEADBFFF
(请注意如何在没有位0xDEADB
改变),所以当我们掩模以取得一致的地址,我们回来0xDEADB000
再次,既然我们已经页对齐.
强制转换uintptr_t
是为了确保我们可以使用数学运算符操作地址,并确保按位反转填充匹配指针所需的所有位(如果它的大小不合适,则可能会反转,然后上转换,突然间你会有左边的一堆零,而不仅仅是右边的,你最终会掩盖指针中的重要位,所以它指向一个完全不同的错误位置).