Vmalloc 和 kmalloc 有什么区别?

我在谷歌上搜索了一下,发现大多数人都提倡使用 kmalloc,因为这样可以保证获得连续的物理内存块。但是,如果找不到您想要的连续 身体上的块,那么似乎 kmalloc也可能失败。
拥有一个连续的内存块有什么好处?具体来说,为什么我需要在 系统呼叫中有一个连续的 身体上的内存块?我为什么不能用 vmalloc呢?
最后,如果要在处理系统调用期间分配内存,是否应该指定 GFP_ATOMIC?系统调用是否在原子上下文中执行?

GFP_ATOMIC
分配是高优先级的,并且 不睡觉。这是国旗 在中断处理程序中使用 其他情况 睡不着。

GFP_KERNEL 这是一个正常的分配,可能会阻塞。这是要使用的标志 在进程上下文代码中睡眠是安全的。

120321 次浏览

拥有一个连续的内存块有什么好处?具体来说,为什么我需要在系统调用中有一个连续的物理内存块?我为什么不能用 vmalloc 呢?

来自 vmalloc频道的谷歌“我感觉很幸运”:

Kmalloc 是首选的方法,只要你不需要非常大的面积。问题是,如果你想在硬件设备之间进行 DMA,你需要使用 kmalloc,你可能需要更大的数据块。解决方案是尽快分配内存,在 记忆变得支离破碎

简短的回答: 下载 Linux 设备驱动程序并阅读关于内存管理的章节。

说真的,有很多与内核内存管理相关的微妙问题需要您理解——我花了很多时间来调试这些问题。

Vmalloc ()很少使用,因为内核很少使用虚拟内存。Kmalloc ()是通常使用的方法,但是您必须知道不同标志的后果,并且您需要一个策略来处理当它失败时发生的情况——特别是如果您像您建议的那样处于一个 interrupt handler 中。

如果物理地址总线(如 PCI)上的 DMA 设备将访问缓冲区,那么您只需要担心使用物理连续内存。问题是,许多系统调用没有办法知道它们的缓冲区是否最终将传递给 DMA 设备: 一旦将缓冲区传递给另一个内核子系统,您就真的不知道它将去哪里。即使内核不使用 DMA 今天,的缓冲区,将来的开发也可能这样做。

Vmalloc 通常比 kmalloc 慢,因为它可能必须将缓冲区空间重新映射到几乎连续的范围。Kmalloc 从不重新映射,但是如果没有使用 GFP _ ATOMIC 调用 kmalloc,它可能会阻塞。

Kmalloc 能够提供的缓冲区大小有限: 128KBytes*)。如果需要非常大的缓冲区,则必须使用 vmalloc 或其他机制,如在引导时保留高内存。

*) < em > 早期的内核也是如此。在最近的内核上(我在2.6.33.2上测试过) ,一个 kmalloc 的最大大小最多为4MB!(我写了一篇相当不错的 详细的文章。)开湾

对于不需要将 GFP _ ATOMIC 传递给 kmalloc ()的系统调用,可以使用 GFP _ KERNEL。你不是一个 interrupt handler: 应用程序代码通过一个陷阱进入内核上下文,它不是一个中断。

另一个区别是 kmalloc 将返回逻辑地址(否则指定 GPF _ HIGHMEM)。逻辑地址放置在“低内存”(物理内存的第一个千兆字节)中,并直接映射到物理地址(使用 _ _ pa 宏进行转换)。这个性质暗示了 kmalloced 内存是连续内存。

另一方面,Vmalloc 能够从“高内存”返回虚拟地址。这些地址不能以直接方式在物理地址中转换(必须使用 virt _ to _ page 函数)。

Robert Love 的 Linux 内核开发(第三版,第12章,第244页)非常清楚地回答了这个问题。

是的,在许多情况下并不需要物理连续内存。Kmalloc 在内核中比 vmalloc 用得更多的主要原因是性能。本书解释说,当使用 vmalloc 分配大内存块时,内核必须将物理上不连续的块(页)映射到单个连续的虚拟内存区域。由于内存实际上是连续的,物理上是不连续的,因此必须向页表添加几个虚拟到物理的地址映射。在最坏的情况下,将有 (缓冲区大小/页面大小)数量的映射添加到页表。

当访问这个缓冲区时,这也增加了 TLB (存储最近的虚拟到物理地址映射的缓存条目)的压力。这可能导致 挣扎

kmalloc()vmalloc()函数是一个简单的接口,用于以字节大小的块获取内核内存。

  1. kmalloc()函数保证页面在物理上是连续的(实际上是连续的)。

  2. vmalloc()函数的工作方式与 kmalloc()类似,只不过它分配的内存实际上是连续的,而不一定是物理上连续的。

在32位系统上,kmalloc ()返回内核逻辑地址(尽管是虚拟地址) ,它具有到物理地址的直接映射(实际上具有常量偏移量)。 这种直接映射确保我们得到一个连续的 RAM 物理块。适用于 DMA,其中我们只给出初始指针,并期望此后为我们的操作连续的物理映射。

Vmalloc ()返回内核虚拟地址,而内核虚拟地址在物理 RAM 上可能没有连续映射。 对于大内存分配非常有用,并且在我们不关心分配给进程的内存在物理 RAM 中是连续的情况下也很有用。

简而言之,vmalloc 和 kmalloc 都可以修复碎片。Vmalloc 使用内存映射来修复外部碎片; kmalloc 使用 plate 来修复内部碎片。无论如何,kmalloc 还有许多其他优势。