分配连续物理内存的方法

5

我知道使用C malloc和posix_memalign可以从进程的虚拟地址空间中分配连续的内存。然而,我想知道是否有一种方法可以分配物理上连续的内存缓冲区?我正在研究利用L2高速缓存的侧信道攻击,所以我想确保我能够访问正确的高速缓存行。


1
值得考虑的是检查POSIX接口、mmap等。至于这是否对侧信道攻击有很大影响,我不清楚。 - gnasher729
1
正如@gnasher729所说,这非常依赖于操作系统,并且通常除了内核本身没有任何理由想要或需要关注物理地址。 - Deduplicator
所以,我在这里做的是使用posix_memalign来分配一个大小为L2_CACHE_SIZE的块,并将其对齐到缓存行的大小。因此,我试图回答的问题是,我是否可以做出这样的假设,即由于分配的虚拟内存对齐到缓存行大小,那么相应的物理内存将是连续的... - Mimo
2个回答

6
你最好、最简单的连续内存方式是从系统请求一个“巨大”的页面。这些页面的可用性取决于你的CPU和内核选项(在x86_64上,通常有2MB的巨大页面,某些CPU还可以使用1GB的页面;其他体系结构可能比此更灵活)。在/proc/meminfo中检查Hugepagesize字段以获取设置中巨大页面的大小。
这些页面可以通过两种方式访问:
  1. 通过向 mmap() 传递 MAP_HUGETLB 标志,可以确保“巨大”虚拟页面对应于连续的物理内存范围。不幸的是,内核能否为您提供“巨大”页面取决于许多因素(当前内存利用布局、内核选项等 - 还请参见 hugepages 内核引导参数)。

  2. 通过从专用 HugeTLB 文件系统映射文件(请参见此处:http://lwn.net/Articles/375096/)。使用 HugeTLB 文件系统,您可以预先配置可用的巨大页面数,以确保必要数量的巨大页面可用。

另一种方法是编写内核模块,该模块将在内核侧分配连续的物理内存,然后根据请求将其映射到您的进程地址空间中。这种方法有时在嵌入式系统中的特殊硬件上使用。当然,仍然不能保证内核侧的内存分配器能够提供适当大小的连续物理地址范围,因此在某些情况下,这些地址范围会在引导时预留(一种愚蠢的方法是在引导时向内核传递 max_addr 参数以使一些 RAM 超出内核的范围)。

0
在(几乎[注1])所有虚拟内存架构中,虚拟内存以“页面”的单位映射到物理内存。页面的大小几乎总是2的幂,并且页面按该大小对齐,因为映射仅使用地址的高位比特来完成。常见的页面大小为4K(12位地址),尽管现代CPU有一种选项可以映射更大的页面,以减小映射表的大小。
由于L2_CACHE_SIZE通常也是2的幂,并且比页面大小小,因此大小为L2_CACHE_SIZE的单个对齐分配必定在单个页面中,因此对齐中的字节也将是物理上连续的。
因此,在这种特殊情况下,您可以确保您分配的内存将是单个缓存行(至少在标准机器架构上)。
注意1:毫无疑问,可能存在不按此方式运作的机器——可能是虚构的。但你正在使用的这台机器不是其中之一。

2
在我的情况下,L2缓存的大小为256K,绝对大于页面大小4K。 - Mimo
1
@Mimo:但你不需要内存是物理上连续的;你只需要单独的缓存行分配成实际的缓存行。L2缓存本身就是由单独的缓存行组成的;两个相邻的缓存行是否映射到相邻的物理(或虚拟)内存是无关紧要的。 - rici

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接