vmalloc和kmalloc有什么区别?

我一直在search,发现大多数人主张使用kmalloc ,因为你保证获得连续的物理内存块。 但是,如果找不到连续的物理块, kmalloc也可能会失败。
拥有连续的内存块有什么好处? 具体而言,为什么我需要在系统调用中拥有连续的物理内存块? 有没有什么原因,我不能只使用vmalloc
最后,如果我在处理系统调用期间分配内存,我应该指定GFP_ATOMIC吗? 在primefaces上下文中执行系统调用吗?

GFP_ATOMIC
分配是高优先级的,不睡觉。 这是在中断处理程序,下半部分和其他你无法入睡的情况下使用的标志。

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

如果物理寻址总线(如PCI)上的DMA设备访问缓冲区,则只需要担心使用物理上连续的内存。 麻烦的是,许多系统调用都无法知道它们的缓冲区是否最终会被传递给DMA设备:一旦你将缓冲区传递给另一个内核子系统,你真的不知道它将要去哪里。 即使内核今天不使用DMA的缓冲区未来的开发也许会这样做。

vmalloc通常比kmalloc慢,因为它可能必须将缓冲区空间重新映射到一个虚拟连续的范围。 kmalloc永远不会重映射,尽pipe如果不用GFP_ATOMIC调用kmalloc可以阻止。

kmalloc的缓冲区大小是有限制的:128 KB *) 。 如果你需要一个非常大的缓冲区,你必须使用vmalloc或其他一些机制,例如在启动时保留高内存。

*) 早先的内核是这样的。 在最近的内核上(我在2.6.33.2上testing过),单个kmalloc的最大大小是4MB! (我在这里写了一个相当详细的post 。) – 开滦

对于系统调用,您不需要将GFP_ATOMIC传递给kmalloc(),则可以使用GFP_KERNEL。 您不是中断处理程序:应用程序代码通过陷阱进入内核上下文,它不是中断。

简短的回答:下载Linux设备驱动程序 ,阅读内存pipe理章节。

严重的是,有很多与内核内存pipe理有关的细微问题需要了解 – 我花了很多时间debugging它的问题。

vmalloc()很less使用,因为内核很less使用虚拟内存。 kmalloc()是通常使用的,但是你必须知道不同标志的后果是什么,你需要一个策略来处理失败时发生的事情 – 特别是如果你在中断处理程序,就像你build议的那样。

罗伯特·洛夫的Linux内核开发(第3版第12章第244页)非常清楚地回答了这个问题。

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

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

拥有连续的内存块有什么好处? 具体而言,为什么我需要在系统调用中拥有连续的物理内存块? 有没有什么原因,我不能只使用vmalloc?

从Google的“我很幸运” vmalloc

kmalloc是首选的方式,只要你不需要很大的区域。 麻烦的是,如果你想从一些硬件设备上做DMA,你需要使用kmalloc,而你可能需要更大的块。 解决scheme是尽可能快地分配内存,然后内存碎片化。

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

  1. kmalloc()函数保证页面在物理上是连续的(并且几乎是连续的)。

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

其他差异之一是kmalloc将返回逻辑地址(否则您指定GPF_HIGHMEM)。 逻辑地址放在“低内存”(在第一个千兆字节的物理内存中),并直接映射到物理地址(使用__pamacros来转换它)。 这个属性意味着kmalloced内存是连续的内存。

另一方面,Vmalloc能够从“高内存”返回虚拟地址。 这些地址不能直接转换为物理地址(您必须使用virt_to_page函数)。

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

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