我知道使用 C malloc 和 posix_memaligh 可以从进程的虚拟地址空间分配连续内存。但是,我想知道是否可以以某种方式分配物理连续内存的缓冲区?我正在调查利用 L2 缓存的侧信道攻击,所以我想确保我可以访问正确的缓存行。
对连续内存的最佳和最简单的方法是从系统请求单个“大”页面。这些的可用性取决于您的 CPU 和内核选项(在 x86_64 上,2MB 大页面通常可用,一些 CPU 也可以处理 1GB 页面;其他架构可能比这更灵活)。检查出Hugepagesize字段/proc/meminfo为您的设置大页面的大小。
这些可以通过两种方式访问:
通过MAP_HUGETLB传递给的标志mmap()。通过这种方式,您可以确保“巨大”的虚拟页面对应于连续的物理内存范围。不幸的是,内核是否可以为您提供一个“巨大的”页面取决于许多因素(内存使用的当前布局、内核选项等 - 另请参阅hugepages内核引导参数)。
通过从专用的 HugeTLB 文件系统映射文件(参见此处:http ://lwn.net/Articles/375096/ )。使用 HugeTLB 文件系统,您可以提前配置可用的大页面数量,以确保有必要数量的大页面可用。
另一种方法是编写一个内核模块,它将在内核端分配连续的物理内存,然后根据请求将其映射到进程的地址空间。这种方法有时用于嵌入式系统中的专用硬件。当然,仍然不能保证内核端内存分配器能够提供适当大小的连续物理地址范围,因此在某些情况下,此类地址范围在启动时预先保留(一种愚蠢的方法是将max_addr参数传递给内核在启动时将一些 RAM 留在内核的范围之外)。
在(几乎[注1])所有虚拟内存架构上,虚拟内存都以“页”为单位映射到物理内存。页的大小(几乎)始终是 2 的幂,并且页按该大小对齐,因为映射仅通过使用地址的高位来完成。尽管现代 CPU 可以选择映射更大的页面以减小映射表的大小,但 4K(12 位地址)的页面大小很常见。
由于L2_CACHE_SIZE通常也是 2 的幂并且小于页面大小,因此任何单个对齐的大小分配L2_CACHE_SIZE都必须位于单个页面中,因此对齐中的字节也将在物理上连续。
因此,在这种特殊情况下,您可以放心,分配的内存将是单个缓存行(至少在标准机器架构上)。
注 1:毫无疑问,有些机器(可能是虚构的)不会以这种方式运行。但和你一起玩的人不是他们中的一员。