我是否正确地假设当进程调用malloc时,可能涉及I / O(交换缓存等)以使内存可用,这反过来意味着它可能会阻塞相当长的时间?因此,我们不应该在linux中有两个版本的malloc,一个说“fast_malloc”,它适合于获得较小的块和&保证不阻止(但当然可能仍然失败OUT_OF_MEMORY)和另一个async_malloc我们可以要求任意大小的空间,但需要回调?
示例:如果我需要较小的内存块来为链表中的项目腾出空间,我可能更喜欢传统的内联malloc,知道操作系统应该能够满足它99.999%的时间或者只是失败。另一个例子:如果我是一个数据库服务器试图分配一个相当大的块来放入索引,我可以选择async_malloc并处理“回调复杂性”。
我提出这个问题的原因是我希望创建高度并发的服务器,每秒处理数十万个Web请求,并且通常会避免处理请求的线程。换句话说,无论何时I / O发生,我都希望它是异步的(比如基于libevent)。不幸的是,我意识到大多数C API缺乏对并发使用的适当支持。例如,无处不在的MySQL C库完全阻塞,而这只是我的服务器广泛使用的一个库。同样,我总是可以通过卸载到另一个线程来模拟非阻塞,但是这远远不如通过完成回调等待结果那么便宜。
答案 0 :(得分:3)
正如凯利姆在评论中所说:
调用
malloc
本身不会导致更多IO。也许你会混淆使用返回的内存而不仅仅是为你分配内存。仅仅因为你要求100MB并不意味着malloc
将立即触发100MB的交换。只有在访问内存时才会发生这种情况。
如果您希望防止在后续访问期间交换等已经分配的内存的长时间延迟,您可以在单独的线程中调用上的mlock
(因此您的流程不会等待mlock
完成)。 mlock
成功后,内存将被物理实例化,并且在munlock
之前无法换出。
答案 1 :(得分:2)
请记住,对malloc()的调用不一定会导致程序要求操作系统获得更多内存。这取决于C运行时的malloc()实现。
仅对于glibc malloc()(取决于你要求多少),返回一个指向运行时已从OS获取的内存的指针。类似地,free()不一定将内存返回给OS。这种方式要快得多。我认为glibc的malloc()也是线程安全的。
有趣的是,这使得C,C ++(以及构建在其上的所有内容)通常与Java和C#等语言相关联。可以说,在像glibc这样的运行时之上构建像Java或C#这样的运行时意味着实际上有更多的工作要比管理内存所需要的工作......除非他们根本不使用malloc()或者新的。
那里有各种各样的分配器,无论你的普通C运行时提供什么,你都可以将你想要的任何一个链接到你的程序中。因此,即使在像* BSD这样的平台上(通常在内存分配方法上更为传统,每次调用malloc(或新)都要求操作系统),你可以实现相同的技巧。
答案 2 :(得分:1)
换句话说,无论何时I / O发生,我都希望它是异步的(比如基于libevent)。
我有个坏消息。任何时候访问内存都有可能阻止I / O.
malloc
本身不太可能阻塞,因为系统调用它只是在数据结构中创建一个条目,告诉内核“在访问它时在某些内存中映射”。这意味着malloc
只会在需要转到内核以映射更多内存并且内核内存不足时才会阻塞,因此它本身必须等待分配其内部数据结构(您可以等待)很长一段时间)或者你使用mlockall
。在触摸内存之前,实际分配可能导致交换的内存不会发生。你自己的记忆可以随时换掉(或者你的程序文本可以被分页),你几乎无法控制它。