{"id":18823600,"url":"https://github.com/yvt/rlsf","last_synced_at":"2025-05-16T12:12:27.140Z","repository":{"id":44340106,"uuid":"354543161","full_name":"yvt/rlsf","owner":"yvt","description":"Constant-time dynamic memory allocator in Rust","archived":false,"fork":false,"pushed_at":"2025-03-25T16:15:11.000Z","size":258,"stargazers_count":97,"open_issues_count":8,"forks_count":6,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-15T17:15:46.105Z","etag":null,"topics":["bare-metal","embedded-systems","library","memory-allocator","real-time-systems","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yvt.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-04-04T12:54:40.000Z","updated_at":"2025-05-13T16:03:26.000Z","dependencies_parsed_at":"2024-12-31T20:14:26.346Z","dependency_job_id":"e3ce65e9-a0a3-4975-aef6-031247a5c9e2","html_url":"https://github.com/yvt/rlsf","commit_stats":{"total_commits":141,"total_committers":3,"mean_commits":47.0,"dds":"0.014184397163120588","last_synced_commit":"e315d64d4ca099573f129aa88e2b4220a808b38e"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yvt%2Frlsf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yvt%2Frlsf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yvt%2Frlsf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yvt%2Frlsf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yvt","download_url":"https://codeload.github.com/yvt/rlsf/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254527099,"owners_count":22085919,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bare-metal","embedded-systems","library","memory-allocator","real-time-systems","rust"],"created_at":"2024-11-08T00:54:08.378Z","updated_at":"2025-05-16T12:12:26.107Z","avatar_url":"https://github.com/yvt.png","language":"Rust","readme":"# rlsf\n    \n\u003cp\u003e\n\u003ca href=\"https://docs.rs/rlsf/\"\u003e\u003cimg src=\"https://docs.rs/rlsf/badge.svg\" alt=\"docs.rs\"\u003e\u003c/a\u003e \u003ca href=\"https://crates.io/crates/rlsf\"\u003e\u003cimg src=\"https://img.shields.io/crates/v/rlsf\"\u003e\u003c/a\u003e \u003cimg src=\"https://img.shields.io/badge/license-MIT%2FApache--2.0-blue\"\u003e\n\u003c/p\u003e\n\nThis crate implements the TLSF (Two-Level Segregated Fit) dynamic memory\nallocation algorithm¹. Requires Rust 1.61.0 or later.\n\n - **Allocation and deallocation operations are guaranteed to complete in\n   constant time.** TLSF is suitable for real-time applications.\n\n - **Fast and small.** You can have both. It was found to be smaller and\n   faster² than most `no_std`-compatible allocator crates.\n\n - **Accepts any kinds of memory pools.** The low-level type\n   [`Tlsf`](#tlsf-core-api) just divides any memory pools you provide\n   (e.g., a `static` array) to serve allocation requests.\n   The high-level type [`GlobalTlsf`](#globaltlsf-global-allocator)\n   automatically acquires memory pages using standard methods on supported\n   systems.\n\n - **This crate supports `#![no_std]`.** It can be used in bare-metal and\n   RTOS-based applications.\n\n\u003c!-- \u003csmall\u003e doesn't work on GitHub --\u003e\n\n\u003csub\u003e¹ M. Masmano, I. Ripoll, A. Crespo and J. Real, \"TLSF: a new dynamic\nmemory allocator for real-time systems,\" *Proceedings. 16th Euromicro\nConference on Real-Time Systems*, 2004. ECRTS 2004., Catania, Italy, 2004,\npp. 79-88, doi: 10.1109/EMRTS.2004.1311009.\u003c/sub\u003e\n\n\u003csub\u003e² Compiled for and measured on a STM32F401 microcontroller using\n\u003ca href=\"https://github.com/yvt/farcri-rs\"\u003eFarCri.rs\u003c/a\u003e.\u003c/sub\u003e\n\n## Measured Performance\n\n![The result of latency measurement on STM32F401 is shown here. rlsf:\n260–320 cycles. buddy-alloc: 340–440 cycles. umm_malloc: 300–700 cycles.\ndlmalloc: 450–750 cycles.\n](https://yvt.jp/files/programs/rlsf/time-cm4f-xf-3.svg)\n\n\u003c!-- `wee_alloc` could not be measured because it ran out of memory too\nearly, probably because of \u003chttps://github.com/rustwasm/wee_alloc/issues/85\u003e\n`umm_malloc` does not support specifying larger alignment values. --\u003e\n\n![The result of code size measurement on WebAssembly is shown here. rlsf:\n1267 bytes, rlsf + pool coalescing: 1584 bytes, wee_alloc: 1910 bytes,\ndlmalloc: 9613 bytes.\n](https://yvt.jp/files/programs/rlsf/size-wasm-xf.svg)\n\n\u003c!-- The latest version at the point of writing was used for each library's\nmeasurement. The exception is `wee_alloc`, for which a fork based on commit\nf26c431df6f was used to make it compile on the latest nightly compiler. --\u003e\n\n## Drawbacks\n\n - **It does not support concurrent access.** A whole pool must be locked\n   for allocation and deallocation. If you use a FIFO lock to protect the\n   pool, the worst-case execution time will be `O(num_contending_threads)`.\n   You should consider using a thread-caching memory allocator (e.g.,\n   TCMalloc, jemalloc) if achieving a maximal throughput in a highly\n   concurrent environment is desired.\n\n - **Segregated freelists with constant-time lookup cause internal\n   fragmentation proportional to free block sizes.** The `SLLEN` paramter\n   allows for adjusting the trade-off between fewer freelists and lower\n   fragmentation.\n\n - **No special handling for small allocations (one algorithm for all\n   sizes).** This may lead to inefficiencies in allocation-heavy\n   applications compared to modern scalable memory allocators, such as\n   glibc and jemalloc.\n\n## Examples\n\n### `Tlsf`: Core API\n\n```rust\nuse rlsf::Tlsf;\nuse std::{mem::MaybeUninit, alloc::Layout};\n\nlet mut pool = [MaybeUninit::uninit(); 65536];\n\n// On 32-bit systems, the maximum block size is 16 \u003c\u003c FLLEN = 65536 bytes.\n// The worst-case internal fragmentation is (16 \u003c\u003c FLLEN) / SLLEN - 2 = 4094 bytes.\n// `'pool` represents the memory pool's lifetime (`pool` in this case).\nlet mut tlsf: Tlsf\u003c'_, u16, u16, 12, 16\u003e = Tlsf::new();\n//                 ^^            ^^  ^^\n//                  |             |  |\n//                'pool           |  SLLEN\n//                               FLLEN\ntlsf.insert_free_block(\u0026mut pool);\n\nunsafe {\n    let mut ptr1 = tlsf.allocate(Layout::new::\u003cu64\u003e()).unwrap().cast::\u003cu64\u003e();\n    let mut ptr2 = tlsf.allocate(Layout::new::\u003cu64\u003e()).unwrap().cast::\u003cu64\u003e();\n    *ptr1.as_mut() = 42;\n    *ptr2.as_mut() = 56;\n    assert_eq!(*ptr1.as_ref(), 42);\n    assert_eq!(*ptr2.as_ref(), 56);\n    tlsf.deallocate(ptr1.cast(), Layout::new::\u003cu64\u003e().align());\n    tlsf.deallocate(ptr2.cast(), Layout::new::\u003cu64\u003e().align());\n}\n```\n\n### `GlobalTlsf`: Global Allocator\n\n`GlobalTlsf` automatically acquires memory pages through platform-specific\nmechanisms. It doesn't support returning memory pages to the system even if\nthe system supports it.\n\n```rust\n#[cfg(all(target_arch = \"wasm32\", not(target_feature = \"atomics\")))]\n#[global_allocator]\nstatic A: rlsf::SmallGlobalTlsf = rlsf::SmallGlobalTlsf::new();\n\nlet mut m = std::collections::HashMap::new();\nm.insert(1, 2);\nm.insert(5, 3);\ndrop(m);\n```\n\n## Details\n\n### Changes from the Original Algorithm\n\n - The end of each memory pool is capped by a sentinel block\n   (a permanently occupied block) instead of a normal block with a\n   last-block-in-pool flag. This simplifies the code a bit and improves\n   its worst-case performance and code size.\n  \n\n## Cargo Features\n\n- `unstable`: Enables experimental features that are exempt from the API\n  stability guarantees.\n\n## License\n\nMIT/Apache-2.0\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyvt%2Frlsf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyvt%2Frlsf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyvt%2Frlsf/lists"}