C ++ - 对齐内存

时间:2016-04-14 18:19:01

标签: 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 );

尤其是最后一行,我对任何事情都不了解......

1 个答案:

答案 0 :(得分:6)

它分配一个指向页面对齐内存块的指针,即PAGES个使用C ++分配器的页数,而不是更多特定于操作系统的专用对齐分配函数(例如POSIX's posix_memalign or C11's aligned_alloc)。

首先,它分配PAGES + 1个内存页面(可能是或不是页面对齐的),然后它向前调整结果指针,使其指向结果中的第一页对齐字节。通过对一个额外的页面进行过度分配,它知道它肯定会有足够大的分配来使PAGES个可用页面超出该点。该程序只需要确定它delete mem完成后,而不是memAligned(删除后者可能会导致程序崩溃,之后由于堆损坏,或只是泄漏内存;它的未定义行为,因此将计算机熔化为渣是一种合法行为。)

最后一行在数值上相当于向上舍入到页面大小的下一个倍数;它将PAGE_SIZE - 1添加到指针(因此,如果指针已经页面对齐,它仍然在同一页面中,否则它将移动到下一页),然后屏蔽掉低位地址(取消"已经页面对齐"情况下的添加,以及在所有其他情况下,将指针重置为mem中未对齐指针之后的第一页开头。

详细信息:~按位反转,因此ADDR_MASK(对于4096字节页可能类似0x00000FFF)变为0xFFFFF000(翻转所有位)。当& - 一个值时,只保留两个操作数中设置的位。举例来说:对于32位指针,我们假设new给了我们0xDEADBEEF,而PAGE_SIZE是4096.添加4095(0xFFF)意味着我们有' 0xDEADCEEE'。然后,我们使用0xFFFFF000进行屏蔽,从而消除低位,为0xDEADC000提供0xDEADBEEFnew之后的第一页对齐地址。 0xDEADB000返回的任何非页面对齐地址都会发生同样的事情。

如果值已经页面对齐,比如说0xFFF,则添加4095 / 0xDEADBFFF会让我们0xDEADB(请注意0xDEADB000中的位没有变化),因此,当我们屏蔽以获取对齐的地址时,我们再次返回uintptr_t,因为我们已经页面对齐。

转换为src -> main -> java -> resources -> test -> java -> resources -> integration-test -> java -> resources 是为了确保我们可以使用数学运算符操作地址,并确保按位反转填充匹配指针所需的所有位(如果它的大小不合适,则为可能会反转,然后上变换,突然你在左边有一堆零,而不是右边的,你最终会掩盖指针中的重要位,所以它指向一个完全不同和错误的地方)。