我已经google了一下,发现大多数人都主张使用kmalloc
,因为你可以保证获得连续的物理内存块.但是,kmalloc
如果找不到您想要的连续物理块,它似乎也会失败.
拥有一块连续的内存块有什么好处?具体来说,为什么我需要在系统调用中拥有连续的物理内存块?我有什么理由不能使用吗?
最后,如果我在处理系统调用期间分配内存,我应该指定吗?系统调用是在原子上下文中执行的吗?vmalloc
GFP_ATOMIC
GFP_ATOMIC
分配是高优先级的,不会睡眠.这是在中断处理程序,下半部分和其他无法睡眠的情况下使用的标志.
GFP_KERNEL
这是正常分配,可能会阻止.这是在安全睡眠时在进程上下文代码中使用的标志.
DGentry.. 90
如果缓冲区将由物理寻址总线上的DMA设备(如PCI)访问,则只需担心使用物理上连续的内存.问题是许多系统调用无法知道它们的缓冲区最终是否会传递给DMA设备:一旦将缓冲区传递给另一个内核子系统,您实际上无法知道它将要去哪里.即使内核今天没有将缓冲区用于DMA ,未来的开发也可能会这样做.
vmalloc通常比kmalloc慢,因为它可能必须将缓冲区空间重新映射到几乎连续的范围.kmalloc从未重新映射,但如果没有使用GFP_ATOMIC调用kmalloc可以阻止.
kmalloc的缓冲区大小有限:128 KB *).如果你需要一个非常大的缓冲区,你必须使用vmalloc或其他一些机制,比如在启动时保留高内存.
*) 这对早期的内核来说是正确的.在最近的内核上(我在2.6.33.2上对此进行了测试),单个kmalloc的最大大小最多为4 MB!(我写了一篇相当详细的帖子.) - kaiwan
对于系统调用,您不需要将GFP_ATOMIC传递给kmalloc(),您可以使用GFP_KERNEL.您不是中断处理程序:应用程序代码通过陷阱进入内核上下文,它不是中断.
如果缓冲区将由物理寻址总线上的DMA设备(如PCI)访问,则只需担心使用物理上连续的内存.问题是许多系统调用无法知道它们的缓冲区最终是否会传递给DMA设备:一旦将缓冲区传递给另一个内核子系统,您实际上无法知道它将要去哪里.即使内核今天没有将缓冲区用于DMA ,未来的开发也可能会这样做.
vmalloc通常比kmalloc慢,因为它可能必须将缓冲区空间重新映射到几乎连续的范围.kmalloc从未重新映射,但如果没有使用GFP_ATOMIC调用kmalloc可以阻止.
kmalloc的缓冲区大小有限:128 KB *).如果你需要一个非常大的缓冲区,你必须使用vmalloc或其他一些机制,比如在启动时保留高内存.
*) 这对早期的内核来说是正确的.在最近的内核上(我在2.6.33.2上对此进行了测试),单个kmalloc的最大大小最多为4 MB!(我写了一篇相当详细的帖子.) - kaiwan
对于系统调用,您不需要将GFP_ATOMIC传递给kmalloc(),您可以使用GFP_KERNEL.您不是中断处理程序:应用程序代码通过陷阱进入内核上下文,它不是中断.
简短回答:下载Linux设备驱动程序并阅读有关内存管理的章节.
说真的,你需要了解许多与内核内存管理相关的细微问题 - 我花了很多时间来调试它的问题.
很少使用vmalloc(),因为内核很少使用虚拟内存.kmalloc()是通常使用的,但你必须知道不同标志的结果是什么,你需要一个策略来处理失败时发生的事情 - 特别是如果你在中断处理程序中,就像你建议的那样.
Robert Love的Linux内核开发(第12章,第244页,第3章)非常清楚地回答了这个问题.
是的,在许多情况下不需要物理上连续的内存.在内核中使用kmalloc比vmalloc更多的主要原因是性能.本书解释说,当使用vmalloc分配大内存块时,内核必须将物理上非连续的块(页面)映射到单个连续的虚拟内存区域.由于存储器实际上是连续的并且物理上是非连续的,因此必须将几个虚拟到物理地址映射添加到页表中.在最坏的情况下,将会有(缓冲区/页面大小的大小)添加到页表的映射数.
当访问此缓冲区时,这还会增加TLB(存储最近虚拟到物理地址映射的缓存条目)的压力.这可能会导致颠簸.
的kmalloc()
&vmalloc()
功能是在字节大小的块获得内核存储器的简单接口.
该kmalloc()
函数保证页面在物理上是连续的(并且几乎是连续的).
该vmalloc()
函数以类似的方式工作kmalloc()
,除了它分配的内存几乎是连续的并且不一定是物理上连续的.
拥有一块连续的内存块有什么好处?具体来说,为什么我需要在系统调用中拥有连续的物理内存块?有什么理由我不能只使用vmalloc吗?
来自谷歌的"我很幸运" vmalloc
:
kmalloc是首选方式,只要你不需要很大的区域.麻烦的是,如果你想从/向某些硬件设备做DMA,你需要使用kmalloc,你可能需要更大的块.解决方案是在内存碎片化之前尽快分配内存.