vmalloc 和 kmalloc 有什么区别?
我用谷歌搜索了一下,发现大多数人都提倡使用 kmalloc
,因为你可以保证获得连续的物理内存块。 但是,如果找不到所需的连续物理块,kmalloc
似乎也会失败。
拥有连续的内存块有什么好处? 具体来说,为什么我需要在系统调用中拥有连续的物理内存块? 有什么原因我不能只使用 vmalloc
吗?
最后,如果我要在处理系统调用期间分配内存,我应该指定 GFP_ATOMIC 吗? 系统调用是在原子上下文中执行的吗?
GFP_ATOMIC
该分配具有高优先级并且 不睡觉。 这是旗帜 在中断处理程序中使用,底部 半场和其他情况 睡不着。
GFP_KERNEL
这是正常分配,可能会阻塞。 这是要使用的标志 当可以安全睡眠时,在进程上下文代码中。
I've googled around and found most people advocating the use of kmalloc
, as you're guaranteed to get contiguous physical blocks of memory. However, it also seems as though kmalloc
can fail if a contiguous physical block that you want can't be found.
What are the advantages of having a contiguous block of memory? Specifically, why would I need to have a contiguous physical block of memory in a system call? Is there any reason I couldn't just use vmalloc
?
Finally, if I were to allocate memory during the handling of a system call, should I specify GFP_ATOMIC
? Is a system call executed in an atomic context?
GFP_ATOMIC
The allocation is high-priority and
does not sleep. This is the flag to
use in interrupt handlers, bottom
halves and other situations where you
cannot sleep.
GFP_KERNEL
This is a normal allocation and might block. This is the flag to use
in process context code when it is safe to sleep.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
Robert Love 的《Linux 内核开发》(第 12 章,第 3 版第 244 页)非常清楚地回答了这个问题。
是的,在许多情况下不需要物理上连续的内存。 kmalloc 在内核中使用多于 vmalloc 的主要原因是性能。 书中解释说,当使用 vmalloc 分配大内存块时,内核必须将物理上不连续的块(页)映射到单个连续的虚拟内存区域。 由于内存实际上是连续的,但物理上是不连续的,因此必须将多个虚拟到物理地址的映射添加到页表中。 在最坏的情况下,将会有(缓冲区大小/页面大小)数量的映射添加到页表中。
访问此缓冲区时,这也会增加 TLB(存储最近的虚拟到物理地址映射的缓存条目)的压力。 这可能会导致系统崩溃。
Linux Kernel Development by Robert Love (Chapter 12, page 244 in 3rd edition) answers this very clearly.
Yes, physically contiguous memory is not required in many of the cases. Main reason for kmalloc being used more than vmalloc in kernel is performance. The book explains, when big memory chunks are allocated using vmalloc, kernel has to map the physically non-contiguous chunks (pages) into a single contiguous virtual memory region. Since the memory is virtually contiguous and physically non-contiguous, several virtual-to-physical address mappings will have to be added to the page table. And in the worst case, there will be (size of buffer/page size) number of mappings added to the page table.
This also adds pressure on TLB (the cache entries storing recent virtual to physical address mappings) when accessing this buffer. This can lead to thrashing.
kmalloc() 和
vmalloc()
函数是一个简单的接口,用于以字节大小的块获取内核内存。kmalloc()
函数保证页面在物理上连续(并且实际上连续)。vmalloc()
函数的工作方式与kmalloc()
类似,只不过它分配的内存只是虚拟连续的,不一定是物理连续的。The
kmalloc()
&vmalloc()
functions are a simple interface for obtaining kernel memory in byte-sized chunks.The
kmalloc()
function guarantees that the pages are physically contiguous (and virtually contiguous).The
vmalloc()
function works in a similar fashion tokmalloc()
, except it allocates memory that is only virtually contiguous and not necessarily physically contiguous.简短回答:下载 Linux 设备驱动程序 并阅读有关内存管理的章节。
说真的,有很多与内核内存管理相关的微妙问题需要理解——我花了很多时间来调试它的问题。
vmalloc() 很少使用,因为内核很少使用虚拟内存。 kmalloc() 是通常使用的,但是您必须知道不同标志的后果是什么,并且您需要一种策略来处理失败时发生的情况 - 特别是如果您处于中断处理程序中,就像您所建议的那样。
Short answer: download Linux Device Drivers and read the chapter on memory management.
Seriously, there are a lot of subtle issues related to kernel memory management that you need to understand - I spend a lot of my time debugging problems with it.
vmalloc() is very rarely used, because the kernel rarely uses virtual memory. kmalloc() is what is typically used, but you have to know what the consequences of the different flags are and you need a strategy for dealing with what happens when it fails - particularly if you're in an interrupt handler, like you suggested.
拥有连续的内存块有什么优点? 具体来说,为什么我需要在系统调用中拥有连续的物理内存块? 我有什么理由不能只使用 vmalloc?
来自 Google 关于
vmalloc
的“手气不错”:kmalloc 是首选方式,只要您不这样做不需要很大的面积。 问题是,如果你想从/到某些硬件设备进行 DMA,你需要使用 kmalloc,并且你可能需要更大的块。 解决方案是在之前尽快分配内存
内存变得碎片化。
What are the advantages of having a contiguous block of memory? Specifically, why would I need to have a contiguous physical block of memory in a system call? Is there any reason I couldn't just use vmalloc?
From Google's "I'm Feeling Lucky" on
vmalloc
:kmalloc is the preferred way, as long as you don't need very big areas. The trouble is, if you want to do DMA from/to some hardware device, you'll need to use kmalloc, and you'll probably need bigger chunk. The solution is to allocate memory as soon as possible, before
memory gets fragmented.
在 32 位系统上,kmalloc() 返回内核逻辑地址(尽管它是虚拟地址),该地址具有到物理地址的直接映射(实际上具有恒定的偏移量)。
这种直接映射确保我们获得连续的物理 RAM 块。 适合 DMA,我们只给出初始指针,并期望此后为我们的操作提供连续的物理映射。
vmalloc() 返回内核虚拟地址,而该地址可能在物理 RAM 上没有连续的映射。
对于大内存分配以及我们不关心分配给进程的内存在物理 RAM 中也是连续的情况很有用。
On a 32-bit system, kmalloc() returns the kernel logical address (its a virtual address though) which has the direct mapping (actually with constant offset) to physical address.
This direct mapping ensures that we get a contiguous physical chunk of RAM. Suited for DMA where we give only the initial pointer and expect a contiguous physical mapping thereafter for our operation.
vmalloc() returns the kernel virtual address which in turn might not be having a contiguous mapping on physical RAM.
Useful for large memory allocation and in cases where we don't care about that the memory allocated to our process is continuous also in Physical RAM.
简而言之,vmalloc 和 kmalloc 都可以修复碎片。 vmalloc 使用内存映射来修复外部碎片; kmalloc 使用slab 来修复内部碎片。 就其价值而言,kmalloc 还具有许多其他优点。
In short, vmalloc and kmalloc both could fix fragmentation. vmalloc use memory mappings to fix external fragmentation; kmalloc use slab to fix internal frgamentation. Fot what it's worth, kmalloc also has many other advantages.
其他区别之一是 kmalloc 将返回逻辑地址(否则您指定 GPF_HIGHMEM)。 逻辑地址放置在“低内存”(物理内存的第一个 GB 中)并直接映射到物理地址(使用 __pa 宏进行转换)。 此属性意味着 kmalloced 内存是连续内存。
另一方面,Vmalloc 能够从“高端内存”返回虚拟地址。 这些地址不能直接转换为物理地址(必须使用 virt_to_page 函数)。
One of other differences is kmalloc will return logical address (else you specify GPF_HIGHMEM). Logical addresses are placed in "low memory" (in the first gigabyte of physical memory) and are mapped directly to physical addresses (use __pa macro to convert it). This property implies kmalloced memory is continuous memory.
In other hand, Vmalloc is able to return virtual addresses from "high memory". These addresses cannot be converted in physical addresses in a direct fashion (you have to use virt_to_page function).
如果缓冲区将由物理寻址总线(如 PCI)上的 DMA 设备访问,则您只需担心使用物理连续内存。 问题在于,许多系统调用无法知道它们的缓冲区最终是否会传递到 DMA 设备:一旦将缓冲区传递到另一个内核子系统,你真的无法知道它将去往何处。 即使内核现在不使用 DMA 缓冲区,未来的开发也可能会这样做。
vmalloc 通常比 kmalloc 慢,因为它可能必须将缓冲区空间重新映射到几乎连续的范围。 kmalloc 永远不会重新映射,但如果不使用 GFP_ATOMIC 调用 kmalloc 可能会阻塞。
kmalloc 可以提供的缓冲区大小受到限制:128 KB*)。 如果您需要一个非常大的缓冲区,则必须使用 vmalloc 或其他一些机制,例如在启动时保留高内存。
对于系统调用,您不需要将 GFP_ATOMIC 传递给 kmalloc(),您可以使用 GFP_KERNEL。 您不是中断处理程序:应用程序代码通过陷阱进入内核上下文,它不是中断。
You only need to worry about using physically contiguous memory if the buffer will be accessed by a DMA device on a physically addressed bus (like PCI). The trouble is that many system calls have no way to know whether their buffer will eventually be passed to a DMA device: once you pass the buffer to another kernel subsystem, you really cannot know where it is going to go. Even if the kernel does not use the buffer for DMA today, a future development might do so.
vmalloc is often slower than kmalloc, because it may have to remap the buffer space into a virtually contiguous range. kmalloc never remaps, though if not called with GFP_ATOMIC kmalloc can block.
kmalloc is limited in the size of buffer it can provide: 128 KBytes*). If you need a really big buffer, you have to use vmalloc or some other mechanism like reserving high memory at boot.
For a system call you don't need to pass GFP_ATOMIC to kmalloc(), you can use GFP_KERNEL. You're not an interrupt handler: the application code enters the kernel context by means of a trap, it is not an interrupt.