我真的很想了解这两行发生了什么
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 );
尤其是最后一行,我对任何事情都不了解......
答案 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
提供0xDEADBEEF
,new
之后的第一页对齐地址。 0xDEADB000
返回的任何非页面对齐地址都会发生同样的事情。
如果值已经页面对齐,比如说0xFFF
,则添加4095 / 0xDEADBFFF
会让我们0xDEADB
(请注意0xDEADB000
中的位没有变化),因此,当我们屏蔽以获取对齐的地址时,我们再次返回uintptr_t
,因为我们已经页面对齐。
转换为src
-> main
-> java
-> resources
-> test
-> java
-> resources
-> integration-test
-> java
-> resources
是为了确保我们可以使用数学运算符操作地址,并确保按位反转填充匹配指针所需的所有位(如果它的大小不合适,则为可能会反转,然后上变换,突然你在左边有一堆零,而不是右边的,你最终会掩盖指针中的重要位,所以它指向一个完全不同和错误的地方)。