C++-对齐内存
C++ - Aligning memory
我真的很想了解这两行发生了什么
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 );
尤其是最后一行,我什么都不懂。。。
它使用C++分配器而不是更特定于操作系统的专用对齐分配函数(例如POSIX的posix_memalign
或C11的aligned_alloc
)来分配指向页面对齐内存块的指针,即PAGES
页数。
首先,它分配PAGES + 1
页内存(可能是页对齐的,也可能不是页对齐的),然后向前调整结果指针,使其指向结果中第一个页对齐的字节。通过过度分配一个额外的页面,它知道它肯定会有足够大的分配,以使PAGES
可用页面超过该点。程序只需要确保它在完成时是delete
的mem
,而不是memAligned
(删除后者可能会导致程序现在崩溃,稍后由于堆损坏,或者只是内存泄漏;这是未定义的行为,因此将计算机熔化是合法行为)。
最后一行在数字上相当于四舍五入到页面大小的下一个倍数;它将PAGE_SIZE - 1
添加到指针(因此,如果指针已经页面对齐,它仍然在同一页中,否则它将移动到下一页),然后屏蔽地址的低位(在"已经页面对齐"的情况下取消添加,在所有其他情况下,将指针重置到mem
中未对齐指针之后的第一页的开头)。
细节:~
是逐位反转的,因此ADDR_MASK
(可能类似于4096字节页面的0x00000FFF
)变成了0xFFFFF000
(翻转所有位)。当&
对一个值求值时,只保留两个操作数中设置的位。举个例子:对于一个32位指针,我们假设new
给了我们0xDEADBEEF
,而PAGE_SIZE
是4096。在4095(0xFFF
)上添加意味着我们有"0xDEADCEE"。然后,我们用0xFFFFF000
屏蔽,它消除了低位,给我们0xDEADC000
,即0xDEADBEEF
之后的第一个页面对齐地址。new
返回的任何非页面对齐地址也会发生同样的情况。
如果该值已经进行了页面对齐,例如0xDEADB000
,则在4095/0xFFF
上相加会得到0xDEADBFFF
(注意0xDEADB
中没有任何位发生变化),因此当我们掩码以获得对齐的地址时,我们会再次返回0xDEADB000
,因为我们已经进行了页对齐。
对CCD_ 29的强制转换是为了确保我们可以使用数学运算符来操作地址,为了确保逐位反转填充匹配指针所需的所有位(如果指针大小不合适,你可能会反转,然后上转换,突然你会在左边有一堆零,而不仅仅是右边,你最终会屏蔽掉指针中的重要位,所以它指向了一个完全不同和错误的地方)。
- 如何理解将半精度指针转换为无符号长指针和相关的内存对齐
- 64位机器上的C++内存对齐
- 不正确的 Vulkan 统一缓冲区内存对齐
- Vulkan 内存对齐要求
- 投射空指针以检查内存对齐情况
- C++中的内存对齐语法
- 继承中的内存对齐规则
- 不了解C 内存对齐
- C++将结构强制转换为 std::矢量<char>内存对齐
- 如何分配内存对齐C++对象数组?
- 是否可以让 std::vector<char> 使用选定的内存对齐方式分配内存
- 有关内存对齐的其他问题
- 是否可以强制对C中的指针参数进行内存对齐
- C++类内存对齐
- 像“float[10][10]”初始化的数组是否已经针对 SIMD/SSE 进行了内存对齐
- 内存对齐 - Sparc(Sun) cc 编译器、Intel(Linux) g++ 编译器、Intel(Windows)
- 内存对齐优化不仅性能,而且内存大小
- Valarray 是否有连续的内存对齐
- 内存对齐与页面对齐
- 在C++中强制实施内存对齐