我周围的一派,发现大多数人都主张使用kmalloc
,因为你保证得到连续的内存物理块。 然而,它也好像kmalloc
,如果你想有一个连续的物理块无法找到可能会失败。
什么是具有一个连续的内存块的优势? 具体来说,为什么我需要有一个连续的内存物理块中的系统调用 ? 是否有任何理由我不能只用vmalloc
?
最后,如果我是一个系统调用的处理过程中分配内存,我应该指定GFP_ATOMIC
? 以原子上下文中执行系统调用?
GFP_ATOMIC
分配高优先级和不睡。 这是在中断处理程序,自下而上半和在那里你可以不睡觉等情况下使用该标志。
GFP_KERNEL
这是一个正常的分配和可能会阻止。 这是在进程上下文代码中使用时是安全的睡觉的标志。
你只需要担心使用物理连续的内存,如果缓冲区将由DMA设备访问在物理寻址总线(如PCI)。 麻烦的是,许多系统调用没有办法知道是否他们的缓冲区最终将传递给DMA设备:一旦你通过缓冲区到另一个内核子系统,你真的无法知道它是要去。 即使内核不使用DMA缓冲区一个未来的发展可能会这么做。
vmalloc的往往比的kmalloc慢,因为它可以具有重新映射缓冲器空间分成一个几乎连续的范围。 kmalloc的永远重新映射,但如果不与GFP_ATOMIC kmalloc的所谓可以阻止。
的kmalloc被限制在缓冲区的大小可以提供:128千字节*)。 如果你需要一个非常大的缓冲区,你必须使用vmalloc的或一些其他类似的机制在引导保留高端内存。
*) 这是早期的内核也是如此。 在最近的内核(我测试了这个在2.6.33.2),单一的kmalloc的最大尺寸可达4 MB! (我写了一个相当关于这个具体职务 。) - kaiwan
对于一个系统调用不需要通过GFP_ATOMIC到kmalloc的(),您可以使用GFP_KERNEL。 你不是一个中断处理程序:应用程序代码的陷阱的方式进入内核上下文,它不是一个中断。
答案很简单:下载Linux设备驱动程序和读取内存管理的章节。
严重的是,有很多的内核内存管理,你需要了解的相关问题微妙 - 我花了我很多时间调试与它的问题。
vmalloc的()是很少使用,因为内核很少使用虚拟内存。 kmalloc的()就是通常使用的,但你要知道什么不同标志的后果是,你需要为处理失败时会发生什么战略 - 特别是如果你是在中断处理程序,像你这样的建议。
Linux内核开发由罗伯特·爱(第12章,244页第3版)回答了这个很清楚。
是的,物理上连续的内存不是很多的情况下需要。 对kmalloc的主要原因是使用了超过vmalloc的内核是性能。 这本书解释,当大的内存块正在使用vmalloc的分配,内核的物理上不连续的数据块(页)映射到一个单一的连续虚拟内存区域。 由于内存几乎是连续的,物理上不连续的,有几个虚拟到物理地址的映射将被添加到页表。 而在最坏的情况下,会出现(缓冲区/页面大小的尺寸)添加到页面表映射的数量。
这也增加上TLB压力(高速缓存条目存储最近虚拟到物理地址映射)访问该缓冲器时。 这可能会导致抖动 。
所述kmalloc()
vmalloc()
函数是用于字节大小的块获得内核存储器的简单接口。
该kmalloc()
函数保证了页面是物理上连续的(并且几乎连续的)。
的vmalloc()
函数以类似的方式工作以kmalloc()
除了它分配存储器,这只是虚拟连续的,不一定物理上连续的。
什么是具有一个连续的内存块的优势? 具体来说,为什么我需要有一个连续的内存物理块中的系统调用? 是否有任何理由我不能只用vmalloc的?
从谷歌的“手气不错” vmalloc
:
kmalloc的是首选的方式,只要你不需要很大的地方。 麻烦的是,如果你想从/到一些硬件设备做DMA,您需要使用kmalloc的,你可能会需要更大的块。 解决的办法是尽快分配内存,内存碎片被前。
一个其他区别是用kmalloc将返回逻辑地址(否则你指定GPF_HIGHMEM)。 逻辑地址被放置在“低存储器”(在物理存储器中的第一千兆字节)和被直接映射到物理地址(使用__pa宏把它转换)。 此属性意味着kmalloced内存是连续的内存。
在另一方面,vmalloc的是能够从“高内存”返回虚拟地址。 这些地址不能在物理地址以直接的方式(你必须使用virt_to_page功能)转换。
在32位的系统中,用kmalloc()返回其具有直接映射(实际上以恒定的偏移量)到物理地址的内核逻辑地址(其虽然虚拟地址)。 这种直接映射确保我们得到的RAM一个连续的物理块。 适用于DMA在这里我们只给出初始指针,并期待着连续的物理映射此后我们的操作。
vmalloc的()返回其又可能不具有对物理RAM的连续映射内核虚拟地址。 有用的大内存配置,在这里我们不关心,分配给我们的进程的内存中的物理RAM也连续病例。