减少 curl 中内存分配操作(malloc)

减少 curl 中内存分配操作(malloc)

今天我在 libcurl 内部又做了一个小改动,使其做更少的 malloc。这一次,泛型链表函数被转换成更少的 malloc (这才是链表函数应有的方式,真的)。

研究 malloc

几周前我开始研究内存分配。这很容易,因为多年前我们 curl 中就已经有内存调试和日志记录系统了。使用 curl 的调试版本,并在我的构建目录中运行此脚本:

#!/bin/sh

export CURL_MEMDEBUG=$HOME/tmp/curlmem.log

./src/curl http://localhost

./tests/memanalyze.pl -v $HOME/tmp/curlmem.log

对于 curl 7.53.1,这大约有 115 次内存分配。这算多还是少?

内存日志非常基础。为了让你有所了解,这是一个示例片段:

MEM getinfo.c:70 free((nil))

MEM getinfo.c:73 free((nil))

MEM url.c:294 free((nil))

MEM url.c:297 strdup(0x559e7150d616)(24)=0x559e73760f98

MEM url.c:294 free((nil))

MEM url.c:297 strdup(0x559e7150d62e)(22)=0x559e73760fc8

MEM multi.c:302 calloc(1,480)=0x559e73760ff8

MEM hash.c:75 malloc(224)=0x559e737611f8

MEM hash.c:75 malloc(29152)=0x559e737a2bc8

MEM hash.c:75 malloc(3104)=0x559e737a9dc8

检查日志

然后,我对日志进行了更深入的研究,我意识到在相同的代码行做了许多小内存分配。我们显然有一些相当愚蠢的代码模式,我们分配一个结构体,然后将该结构添加到链表或哈希,然后该代码随后再添加另一个小结构体,如此这般,而且经常在循环中执行。(我在这里说的是我们,不是为了责怪某个人,当然大部分的责任是我自己……)

这两种分配操作将总是成对地出现,并被同时释放。我决定解决这些问题。做非常小的(小于 32 字节)的分配也是浪费的,因为非常多的数据将被用于(在 malloc 系统内)跟踪那个微小的内存区域。更不用说堆碎片了。

因此,将该哈希和链表代码修复为不使用 malloc 是快速且简单的方法,对于最简单的 “curl ” 传输,它可以消除 20% 以上的 malloc。

此时,我根据大小对所有的内存分配操作进行排序,并检查所有最小的分配操作。一个突出的部分是在 curl_multi_wait() 中,它是一个典型的在 curl 传输主循环中被反复调用的函数。对于大多数典型情况,我将其转换为使用堆栈。在大量重复的调用函数中避免 malloc 是一件好事。

重新计数

现在,如上面的脚本所示,同样的 curl localhost 命令从 curl 7.53.1 的 115 次分配操作下降到 80 个分配操作,而没有牺牲任何东西。轻松地有 26% 的改善。一点也不差!

由于我修改了 curl_multi_wait(),我也想看看它实际上是如何改进一些稍微更高级一些的传输。我使用了 multi-double.c 示例代码,添加了初始化内存记录的调用,让它使用 curl_multi_wait(),并且并行下载了这两个 URL:

http://www.example.com/

http://localhost/512M

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/13480.html