40 个大型 C 项目的内存管理调查

The Consensus 跟踪的 40 个主要 C 项目的调查显示,只有 8 个项目仅使用 malloc/free 进行分配,只有 2 个项目从未使用 malloc/free,15 个项目在某个阶段使用了区域(region),7 个项目主要使用区域进行分配,5 个项目主要使用垃圾回收进行分配,3 个项目主要使用引用计数进行分配。
您作为订阅者正在提前访问本文。您的支持让这样的文章成为可能。谢谢。
C 语言以需要使用 malloc 和 free 进行手动内存管理而闻名。虽然许多大型项目确实是这样管理内存的,但许多项目也实现了更高级的内存管理原语,例如区域(在一个区域内分配的对象无需手动释放,释放一个区域会一次性释放该区域内分配的所有对象)、引用计数(手动递增和递减未完成的引用,仅当对象的引用计数归零时才释放该对象)、使用编译器扩展的基于作用域的清理,并且一些主要的 C 项目甚至实际实现了垃圾回收(完全自动的内存管理)。
程序员有时会认为,以严谨著称的项目会远离纯手动内存管理。但以正确性著称的 SQLite 100% 手动分配,而 cURL 和 Redis 主要手动分配(分别为 94% 和 79%),仅对其部分对象使用引用计数。另一个令人惊讶的发现是,Linux 和 QEMU 在过去几年中开始使用作用域清理规则(即编译器扩展)来自动清理内存,例如 Linux 的 __free(kfree) 和 QEMU 的 g_autofree。
The Consensus 跟踪并索引了 400 多个主要软件基础设施项目的代码。本文调查了该群体中的 40 个 C 项目,排除了测试代码、第三方代码和示例。
多数分配策略
为了发现多数分配策略,我们统计了分配调用点(这当然是一个有限的指标,未考虑子区域或分配大小等)。seL4 是本文许多方面的例外,因为它根本没有堆。
8 个项目仅使用 malloc 进行分配,未实现任何其他通用的更高级分配策略。这些项目是:brotli、FreeRTOS、HAProxy、libdeflate、lz4、SQLite、xz-utils 和 zlib。
16 个项目主要(但并非完全)使用 malloc 进行分配。
| Project | Manual % | Region % | Garbage Collector % | Reference Counting % |
|---|---|---|---|---|
| PgBouncer | 98 | 0 | 0 | 2 |
| tmux | 98 | 0 | 0 | 2 |
| git | 96 | 3 | 0 | 0 |
| curl | 94 | 0 | 0 | 6 |
| dqlite | 92 | 0 | 0 | 8 |
| QEMU | 86 | 0 | 0 | 14 |
| Vim | 85 | 0 | 0 | 15 |
| Redis | 79 | 0 | 0 | 21 |
| Neovim | 74 | 10 | 0 | 15 |
| universal-ctags | 72 | 0 | 0 | 28 |
| Linux | 71 | 29 | 0 | 0 |
| zstd | 70 | 30 | 0 | 0 |
| tree-sitter | 62 | 0 | 0 | 38 |
| Erlang | 57 | 0 | 39 | 4 |
| PostGIS | 54 | 46 | 0 | 1 |
| Xen | 51 | 49 | 0 | 0 |
7 个项目主要(如果不是全部)使用区域系统进行分配。在基于区域的分配器中,对象在区域内分配。释放该区域会释放该区域内的所有对象。有时区域可以嵌套。有时您可能仍然需要手动释放区域内分配的对象。
| Project | Region % | Manual % | Garbage Collector % |
|---|---|---|---|
| pgvector | 100 | 0 | 0 |
| TimescaleDB | 100 | 0 | 0 |
| Citus | 99 | 1 | 0 |
| httpd | 98 | 2 | 0 |
| nginx | 92 | 8 | 0 |
| Postgres | 78 | 22 | 0 |
| llama.cpp (ggml) | 65 | 35 | 0 |
还有 5 个项目主要使用垃圾回收进行分配。
| Project | Garbage Collector % | Manual % | Region % |
|---|---|---|---|
| Ruby | 82 | 18 | 0 |
| Julia | 80 | 20 | 0 |
| Emacs | 77 | 23 | 0 |
| OCaml | 62 | 38 | 0 |
| Lua | 60 | 40 | 0 |
像 {{NAME_ab12cd34}} 这样写出的值是真实值的占位符。在回复和工具调用中都完全按书写原样使用它们:它们会在任何内容运行之前被填入真实值。不要要求验证它们,也不要用示例替换它们。
40 个大型 C 项目的内存管理调查
3 个项目主要分配引用计数对象。
| 项目 | 引用计数 % | 手动 % | 区域 % |
|---|---|---|---|
| CPython | 85 | 13 | 2 |
| PHP | 62 | 36 | 2 |
| Perl | 62 | 38 | 0 |
所有项目
在所有受调查项目中,附有指向其各种分配策略的示例链接。
| 项目 | free/malloc | 区域 | 垃圾回收器 | 引用计数 | 作用域清理 |
|---|---|---|---|---|---|
| sqlite | sqlite3_mprintf , sqlite3_free | 无 | 无 | 无 | 无 |
| haproxy | strdup , free | 无 | 无 | 无 | 无 |
| pgbouncer | malloc , free | 无 | 无 | strpool_decref | 无 |
| redis | zmalloc , zfree | 无 | 无 | decrRefCount | 无 |
| git | xstrdup , free | mem_pool_alloc , mem_pool_init | 无 | blame_origin_decref | 无 |
| tmux | xstrdup , free | 无 | 无 | server_client_unref | 无 |
| vim | vim_strsave , vim_free | 无 | garbage_collect | dict_unref | 无 |
| neovim | xstrdup , xfree | arena_memdupz , arena_mem_free | 无 | tv_dict_unref | 无 |
| tree-sitter | ts_malloc , ts_free | 无 | 无 | ts_subtree_release | 无 |
| universal-ctags | eStrdup , eFree | 无 | 无 | es_object_unref | 无 |
| zstandard | malloc , free | ZSTD_cwksp_reserve_aligned64 , ZSTD_cwksp_init | 无 | 无 | 无 |
| zlib | ZALLOC , ZFREE | 无 | 无 | 无 | 无 |
| xz-utils | lzma_alloc , lzma_free | 无 | 无 | 无 | 无 |
| lz4 | ALLOC , FREEMEM | 无 | 无 | 无 | 无 |
| brotli | BROTLI_ALLOC , BROTLI_FREE | 无 | 无 | 无 | 无 |
| libdeflate | libdeflate_aligned_malloc , libdeflate_aligned_free | 无 | 无 | 无 | 无 |
| freertos | pvPortMalloc , vPortFree | 无 | 无 | 无 | 无 |
| dqlite | raft_malloc , raft_free | 无 | 无 | logRelease | 无 |
| curl | curlx_calloc , curlx_free | 无 | 无 | Curl_creds_unlink | 无 |
| xen | xzalloc , xfree | GCSPRINTF , GC_INIT | 无 | 无 | 无 |
| qemu | g_new0 , g_free | 无 | 无 | object_unref | g_autofree |
| linux | kzalloc_obj , kfree | devm_kzalloc | 无 | kref_put | __free |
| postgresql | pg_strdup , pg_free | palloc , MemoryContextReset | 无 | 无 | 无 |
| pgvector | 无 | palloc , MemoryContextDelete | 无 | 无 | 无 |
| citus | strdup , free | palloc0 , MemoryContextReset | 无 | 无 | 无 |
| timescaledb | 无 | palloc , AllocSetContextCreate | 无 | 无 | 无 |
| postgis | lwalloc , lwfree | palloc , AllocSetContextCreate | 无 | shared_gserialized_unref | 无 |
| nginx | ngx_alloc , ngx_free | ngx_create_pool , ngx_destroy_pool | 无 | 无 | 无 |
| apache-http-server | apr_bucket_alloc , apr_bucket_free | apr_pool_create , apr_pool_clear | 无 | 无 | 无 |
| llama-cpp (ggml C) | calloc , free | ggml_new_tensor_1d , ggml_free | 无 | 无 | 无 |
发现了错误?有问题或评论?请写信给编辑。