malloc不应该是异步的吗?



假设当一个进程调用malloc时,可能会涉及I/O(交换缓存等)以使内存可用,这反过来意味着它可以阻塞相当多的时间,我是否正确?因此,我们在linux中不应该有两个版本的malloc吗?一个说"fast_malloc",它适用于获取较小的块&保证不阻塞(但当然可能仍然失败与OUT_OF_MEMORY)和另一个async_malloc,我们可以要求任意大小的空间,但需要一个回调?

示例:如果我需要更小的内存块来为链表中的项腾出空间,我可能更喜欢传统的内联malloc,因为我知道操作系统应该能够在99.999%的时间内满足它,否则就会失败。另一个例子:如果我是一个DB服务器,试图分配一个相当大的块来放置索引,我可能会选择async_malloc并处理"回调复杂性"。

我提出这个问题的原因是我希望创建每秒处理数十万个web请求的高并发服务器,并且通常避免线程处理请求。换句话说,任何时候发生I/O,我都希望它是异步的(比如基于libevent)。不幸的是,我意识到大多数C api缺乏对并发使用的适当支持。例如,无处不在的MySQL C库是完全阻塞的,这只是我的服务器广泛使用的一个库。同样,我可以通过卸载到另一个线程来模拟非阻塞,但这远不如通过完成回调等待结果来得便宜。

正如kaylum在评论中所说:

调用malloc本身不会导致更多的IO。也许您混淆了使用返回的内存和仅仅为您分配内存。仅仅因为您要求100MB并不意味着malloc将立即触发100MB的交换。这只会在你访问内存时发生。

如果你想在随后访问分配的内存期间防止长时间的交换延迟等,你可以在一个单独的线程中调用mlock(这样你的进程就不会因为等待mlock完成而停滞)。一旦mlock操作成功,内存将被物理实例化,并且在munlock之前不能被换出。

请记住,调用malloc()并不一定会导致程序向操作系统请求更多内存。这取决于C运行时对malloc()的实现。

对于glibc, malloc()仅仅(取决于您请求的大小)返回一个指向运行时已经从操作系统获得的内存的指针。类似地,free()不一定将内存返回给操作系统。那样会快很多。我认为glibc的malloc()也是线程安全的。

有趣的是,这给了C、c++(以及在其上构建的所有东西)通常与Java和c#等语言相关的相同类型的属性。可以说,在像glibc这样的运行时之上构建像Java或c#这样的运行时意味着实际上有比管理内存所需的更多的工作要做……除非它们根本没有使用malloc()或new。

有各种各样的分配器,你可以将任何你想要的分配器链接到你的程序中,而不管你的普通C运行时提供什么。因此,即使在像*BSD这样的平台上(通常在内存分配方法上要传统得多,每次调用malloc()或new时都要询问操作系统),您也可以实现相同的技巧。

换句话说,任何时候发生I/O,我都希望它是异步的(比如基于libevent)。

我有坏消息要告诉你。任何时候访问内存都有阻塞I/o的风险。

malloc本身不太可能阻塞,因为系统调用它只是在数据结构中创建一个条目,告诉内核"当它被访问时映射到这里的一些内存"。这意味着malloc只在需要到内核映射更多内存时才会阻塞,或者内核内存不足,因此它自己必须等待分配其内部数据结构(这时您可以等待相当长的时间),或者您使用mlockall。可能导致交换的实际内存分配直到触及内存时才会发生。你自己的内存可以在任何时候被换出(或者你的程序文本可以被换出),你几乎无法控制它。

相关内容

  • 没有找到相关文章

最新更新