memory-admission
memory-admission is a Rust admission gate for parallel work that should slow down when the host or cgroup is under memory pressure.
It provides synchronous gates, Tokio-friendly gates, and weighted gates for jobs that can estimate their memory cost in bytes. Use it when a worker count alone is not enough to protect a machine from swap thrashing or out-of-memory pressure.
Source is hosted at Codeberg.
Installation
Add the crate to your Rust project:
cargo add memory-admission
The default feature set enables the synchronous API, the async API, and the cross-platform sysinfo provider.
To choose a smaller API surface, disable default features and opt in:
[dependencies]
memory-admission = { version = "0.1.0", default-features = false, features = ["async"] }
Quick Start
Use an admission gate around the work that creates memory pressure.
#![allow(unused)]
fn main() {
use memory_admission::sync::AdmissionGate;
let gate = AdmissionGate::new_default();
let permit = gate.acquire();
// Run memory-sensitive work while the permit is held.
drop(permit);
}
For async workloads, use the Tokio-friendly gate:
#![allow(unused)]
fn main() {
use memory_admission::r#async::AdmissionGate;
let gate = AdmissionGate::new_default();
let permit = gate.acquire().await;
// Run memory-sensitive async work while the permit is held.
drop(permit);
}
Providers
A memory provider returns current memory usage as a fraction in the inclusive range [0.0, 1.0].
The default provider selection is:
- Linux cgroup-v2 accounting when the current process is in a cgroup-v2 hierarchy.
- Linux
/proc/meminfo. sysinfoon non-Linux targets when thesysinfofeature is enabled.
Custom providers can implement MemoryProvider for other memory sources such as NUMA-specific accounting, container runtimes, or test fixtures.
Hysteresis
The gate enters a throttled state when memory usage exceeds Config::max_ram_fraction.
It resumes only after usage drops below max_ram_fraction - resume_hysteresis. This prevents a cycle where releasing one task admits another task immediately and pushes memory usage back over the limit.
Failure Behavior
Provider failures should not fail user work.
If the memory provider fails during initialization, the gate falls back to thread-cap-only admission and logs the reason. Later provider failures during acquisition also disable memory throttling once and allow callers to continue.
This behavior is useful in sandboxes or restricted containers where /proc/meminfo, cgroup files, or platform APIs can be unavailable.
Synchronous Gate
The synchronous gate is backed by std::sync::Condvar and is intended for thread-pool-based work.
#![allow(unused)]
fn main() {
use memory_admission::sync::AdmissionGate;
let gate = AdmissionGate::new_default();
let permit = gate.acquire();
// Do memory-sensitive work.
drop(permit);
}
Dropping the permit releases the admission slot and wakes waiting callers when appropriate.
Async Gate
The async gate is backed by tokio::sync::Notify and is intended for Tokio task fanout and stream pipelines.
#![allow(unused)]
fn main() {
use memory_admission::r#async::AdmissionGate;
let gate = AdmissionGate::new_default();
let permit = gate.acquire().await;
// Do memory-sensitive async work.
drop(permit);
}
Hold the permit for the lifetime of the operation that contributes to memory pressure.
Weighted Gates
Weighted gates reserve the caller’s declared byte weight until the returned permit is dropped.
#![allow(unused)]
fn main() {
use memory_admission::weighted::{AsyncAdmissionGate, WeightedConfig};
let config = WeightedConfig::validated_default();
let gate = AsyncAdmissionGate::new(
config,
memory_admission::providers::default_provider(),
);
let permit = gate.acquire(512 * 1024 * 1024).await;
// Run work expected to commit about 512 MiB.
drop(permit);
}
Oversized jobs wait until the gate is otherwise empty, then run alone so they do not deadlock the system.
Nix
The flake builds the crate with crane through git+https://codeberg.org/caniko/rs-harbor.git.
nix build
nix flake check
nix develop
The website and documentation are available as separate package outputs:
nix build .#website
nix build .#docs
nix build .#site
The combined site output serves the Zola site at the root and mdBook documentation under /docs/.