Newshot

Memory management in 40 major C projects, a survey

Original text(via Lobsters)

Memory management in 40 major C projects, a survey

题图
题图

A survey of 40 major C projects tracked by The Consensus shows only 8 projects allocate solely with malloc/free, only 2 projects allocate without ever using malloc/free, 15 projects make use of regions at some point, 7 projects primarily use regions to allocate, 5 primarily use garbage collection to allocate, and 3 primarily use reference counting to allocate.

You are getting early access to this article as a subscriber. Your support makes articles like this possible. Thank you.

C is well known for requiring manual memory management with malloc and free. And while many major projects do actually manage memory like this, many projects also implement higher-level memory management primitives such as regions (where objects allocated within a region need not be manually freed, freeing a region frees all objects allocated within the region at once), reference counting (manually incrementing and decrementing outstanding references, freeing an object only when its references go to zero), scope-based cleanup using compiler extensions, and a number of major C projects even actually implement garbage collection (fully automatic memory management).

Programmers sometimes assume that projects famous for diligence lean away from purely manual memory management. But SQLite, famous for correctness, allocates 100% manually while cURL and Redis allocate mostly manually (94% and 79%), reference counting only some of their objects. Another surprising finding is that Linux and QEMU in the last few years have been starting to use scope cleanup rules (i.e. compiler extensions) to automatically clean up memory, such as Linux's __free(kfree) and QEMU's g_autofree.

The Consensus tracks and indexes code for over 400 major software infrastructure projects. This article surveys 40 of the C projects within this group, excluding test code, third-party code, and examples.

Majority allocation strategy

To discover majority allocation we count allocation call sites (which is certainly a limited metric, not accounting for sub-region or size of allocation, etc.). seL4 is an exception to much of this article since it has no heap at all.

8 projects solely allocate with malloc, implementing no other general higher-level strategy for allocating. These projects are: brotli, FreeRTOS, HAProxy, libdeflate, lz4, SQLite, xz-utils, and zlib.

16 projects primarily, but not exclusively, allocate with malloc.

ProjectManual %Region %Garbage Collector %Reference Counting %
PgBouncer98002
tmux98002
git96300
curl94006
dqlite92008
QEMU860014
Vim850015
Redis790021
Neovim7410015
universal-ctags720028
Linux712900
zstd703000
tree-sitter620038
Erlang570394
PostGIS544601
Xen514900

7 projects primarily, if not all exclusively, allocate with a region system. With region based allocators, objects are allocated within a region. Freeing the region frees all objects within the region. Sometiems regions can be nested. And sometimes you might still manually free an object allocated within a region.

ProjectRegion %Manual %Garbage Collector %
pgvector10000
TimescaleDB10000
Citus9910
httpd9820
nginx9280
Postgres78220
llama.cpp (ggml)65350

And 5 projects primarily allocate with a garbage collector.

ProjectGarbage Collector %Manual %Region %
Ruby82180
Julia80200
Emacs77230
OCaml62380
Lua60400

3 projects primarily allocate reference-counted objects.

ProjectReference Counting %Manual %Region %
CPython85132
PHP62362
Perl62380

All projects

Across all surveyed projects, with links to their various allocation strategies by example.

Projectfree/mallocRegionGarbage CollectorReference CountsScope Cleanup
sqlitesqlite3_mprintf , sqlite3_freenonenonenonenone
haproxystrdup , freenonenonenonenone
pgbouncermalloc , freenonenonestrpool_decrefnone
rediszmalloc , zfreenonenonedecrRefCountnone
gitxstrdup , freemem_pool_alloc , mem_pool_initnoneblame_origin_decrefnone
tmuxxstrdup , freenonenoneserver_client_unrefnone
vimvim_strsave , vim_freenonegarbage_collectdict_unrefnone
neovimxstrdup , xfreearena_memdupz , arena_mem_freenonetv_dict_unrefnone
tree-sitterts_malloc , ts_freenonenonets_subtree_releasenone
universal-ctagseStrdup , eFreenonenonees_object_unrefnone
zstandardmalloc , freeZSTD_cwksp_reserve_aligned64 , ZSTD_cwksp_initnonenonenone
zlibZALLOC , ZFREEnonenonenonenone
xz-utilslzma_alloc , lzma_freenonenonenonenone
lz4ALLOC , FREEMEMnonenonenonenone
brotliBROTLI_ALLOC , BROTLI_FREEnonenonenonenone
libdeflatelibdeflate_aligned_malloc , libdeflate_aligned_freenonenonenonenone
freertospvPortMalloc , vPortFreenonenonenonenone
dqliteraft_malloc , raft_freenonenonelogReleasenone
curlcurlx_calloc , curlx_freenonenoneCurl_creds_unlinknone
xenxzalloc , xfreeGCSPRINTF , GC_INITnonenonenone
qemug_new0 , g_freenonenoneobject_unrefg_autofree
linuxkzalloc_obj , kfreedevm_kzallocnonekref_put__free
postgresqlpg_strdup , pg_freepalloc , MemoryContextResetnonenonenone
pgvectornonepalloc , MemoryContextDeletenonenonenone
citusstrdup , freepalloc0 , MemoryContextResetnonenonenone
timescaledbnonepalloc , AllocSetContextCreatenonenonenone
postgislwalloc , lwfreepalloc , AllocSetContextCreatenoneshared_gserialized_unrefnone
nginxngx_alloc , ngx_freengx_create_pool , ngx_destroy_poolnonenonenone
apache-http-serverapr_bucket_alloc , apr_bucket_freeapr_pool_create , apr_pool_clearnonenonenone
llama-cpp (ggml C)calloc , freeggml_new_tensor_1d , ggml_freenonenonenone

Noticed a mistake? Have a question or comment? Write to the editor.

Comments

The text above was extracted automatically from the source page and may miss images, tables or code blocks. The original is authoritative.

Published by Lobsters
This site only summarises and aggregates; copyright stays with the original author. Headlines and summaries follow the source — where they differ, the original wins.
Read the original ↗