compose_library/gc/
clean.rs1use compose_library::gc::trigger::GcEvent;
2use compose_library::{Heap, Trace};
3use slotmap::SecondaryMap;
4use std::collections::VecDeque;
5use std::time::{Duration, Instant};
6
7impl Heap {
8 pub fn maybe_gc(&mut self, root: &impl Trace) -> Option<CleanResult> {
9 if !self.policy.on_event(&GcEvent::MaybeGc, &self.data()) {
10 return None;
11 }
12 Some(self.clean(root))
13 }
14
15 pub fn clean(&mut self, root: &impl Trace) -> CleanResult {
16 let start = Instant::now();
17 let mut worklist = VecDeque::new();
18
19 root.visit_refs(&mut |key| worklist.push_back(key));
20
21 let mut marked = SecondaryMap::new();
23 while let Some(key) = worklist.pop_front() {
24 if marked.insert(key, ()).is_some() {
25 continue;
27 }
28
29 let Some(item) = self.map.get(key) else {
30 continue;
32 };
33
34 item.visit_refs(&mut |key| worklist.push_back(key));
35 }
36
37 let mut sweeped = 0;
38 let total_allocated = self.map.len();
39
40 self.map.retain(|key, _| {
42 let keep = marked.contains_key(key);
43 if !keep {
44 sweeped += 1;
45 }
46 keep
47 });
48
49 let gc_duration = start.elapsed();
50
51 let result = CleanResult {
52 sweeped,
53 total_allocated,
54 gc_duration,
55 };
56
57 self.policy.after_gc(&result, &self.data());
58
59 result
60 }
61}
62
63#[derive(Debug)]
64pub struct CleanResult {
65 pub sweeped: usize,
67 pub total_allocated: usize,
69 pub gc_duration: Duration,
70}
71
72impl CleanResult {
73 pub fn marked(&self) -> usize {
74 self.total_allocated - self.sweeped
75 }
76}