use rusty_alloc::alloc::{free, malloc};
use std::sync::atomic::Ordering;
const WAVES: usize = 8;
const PER_WAVE: usize = 8;
const BLOCKS: usize = 512;
fn churn_thread() {
let mut v = Vec::with_capacity(BLOCKS);
for i in 0..BLOCKS {
let n = 4096 + (i * 997) % 262_144; let p = malloc(n);
assert!(!p.is_null());
unsafe { core::ptr::write_bytes(p, 0x5A, n) };
v.push((p, n));
}
for (p, _) in v.drain(..BLOCKS - 8) {
unsafe { free(p) };
}
core::mem::forget(v);
}
#[cfg_attr(miri, ignore)]
#[test]
fn abandoned_segments_should_not_accumulate_across_thread_waves() {
println!("{:>5} {:>18}", "wave", "abandoned_segments");
let mut peak = 0usize;
for w in 0..WAVES {
let hs: Vec<_> = (0..PER_WAVE)
.map(|_| std::thread::spawn(churn_thread))
.collect();
for h in hs {
h.join().unwrap();
}
let ab = rusty_alloc::init::ABANDONED_COUNT.load(Ordering::Relaxed);
peak = peak.max(ab);
println!("{w:>5} {ab:>18}");
}
let mut keep = Vec::new();
for i in 0..2048 {
let p = malloc(4096 + (i * 131) % 65536);
assert!(!p.is_null());
keep.push(p);
}
let after = rusty_alloc::init::ABANDONED_COUNT.load(Ordering::Relaxed);
for p in keep {
unsafe { free(p) };
}
println!("\npeak abandoned = {peak}, after a fresh allocation burst = {after}");
println!(
"Each abandoned segment is 32 MiB of address space. If `after` stays \
near `peak`, adoption is not reclaiming them and that is the RSS tail."
);
}