1use std::collections::{HashMap, HashSet, VecDeque};
8use std::sync::{Arc, RwLock};
9use std::time::{Duration, Instant};
10
11pub struct GarbageCollectionEngine {
13 config: GCConfig,
15 stats: GCStats,
17 collectors: Vec<Box<dyn GarbageCollector>>,
19 memory_regions: HashMap<usize, MemoryRegion>,
21 reference_tracker: ReferenceTracker,
23 scheduler: GCScheduler,
25 performance_history: VecDeque<GCPerformance>,
27}
28
29#[derive(Debug, Clone)]
31pub struct GCConfig {
32 pub auto_gc: bool,
34 pub gc_threshold: f64,
36 pub max_pause_time: Duration,
38 pub enable_generational: bool,
40 pub enable_incremental: bool,
42 pub enable_concurrent: bool,
44 pub young_gen_ratio: f64,
46 pub survivor_ratio: f64,
48 pub tenuring_threshold: u32,
50 pub enable_stats: bool,
52 pub preferred_algorithm: GCAlgorithm,
54 pub parallel_gc: bool,
56 pub gc_threads: usize,
58}
59
60impl Default for GCConfig {
61 fn default() -> Self {
62 Self {
63 auto_gc: true,
64 gc_threshold: 0.8,
65 max_pause_time: Duration::from_millis(10),
66 enable_generational: true,
67 enable_incremental: true,
68 enable_concurrent: false,
69 young_gen_ratio: 0.3,
70 survivor_ratio: 0.1,
71 tenuring_threshold: 15,
72 enable_stats: true,
73 preferred_algorithm: GCAlgorithm::Generational,
74 parallel_gc: true,
75 gc_threads: 2,
76 }
77 }
78}
79
80#[derive(Debug, Clone, PartialEq)]
82pub enum GCAlgorithm {
83 MarkSweep,
85 Copying,
87 Generational,
89 Incremental,
91 Concurrent,
93 ReferenceCounting,
95 Adaptive,
97}
98
99#[derive(Debug, Clone, Default)]
101pub struct GCStats {
102 pub total_cycles: u64,
104 pub total_gc_time: Duration,
106 pub total_bytes_collected: u64,
108 pub total_objects_collected: u64,
110 pub average_pause_time: Duration,
112 pub max_pause_time: Duration,
114 pub gc_efficiency: f64,
116 pub young_gen_collections: u64,
118 pub old_gen_collections: u64,
120 pub promotion_rate: f64,
122 pub reclaim_rate: f64,
124 pub gc_overhead: f64,
126 pub last_gc_time: Option<Instant>,
128}
129
130#[derive(Debug, Clone)]
132pub struct MemoryRegion {
133 pub base_addr: usize,
135 pub size: usize,
137 pub generation: u32,
139 pub objects: HashMap<usize, ObjectMetadata>,
141 pub free_bitmap: Vec<u64>,
143 pub last_collection: Option<Instant>,
145 pub collection_count: u32,
147 pub utilization: f64,
149}
150
151#[derive(Debug, Clone)]
153pub struct ObjectMetadata {
154 pub address: usize,
156 pub size: usize,
158 pub type_id: u32,
160 pub ref_count: u32,
162 pub marked: bool,
164 pub age: u32,
166 pub last_access: Option<Instant>,
168 pub references: Vec<usize>,
170}
171
172pub struct ReferenceTracker {
174 reference_graph: HashMap<usize, HashSet<usize>>,
176 reverse_references: HashMap<usize, HashSet<usize>>,
178 root_references: HashSet<usize>,
180 write_barrier_log: VecDeque<WriteBarrierEntry>,
182}
183
184#[derive(Debug, Clone)]
186pub struct WriteBarrierEntry {
187 pub source: usize,
188 pub target: usize,
189 pub timestamp: Instant,
190}
191
192impl Default for ReferenceTracker {
193 fn default() -> Self {
194 Self::new()
195 }
196}
197
198impl ReferenceTracker {
199 pub fn new() -> Self {
200 Self {
201 reference_graph: HashMap::new(),
202 reverse_references: HashMap::new(),
203 root_references: HashSet::new(),
204 write_barrier_log: VecDeque::new(),
205 }
206 }
207
208 pub fn add_reference(&mut self, from: usize, to: usize) {
210 self.reference_graph.entry(from).or_default().insert(to);
211 self.reverse_references.entry(to).or_default().insert(from);
212 }
213
214 pub fn remove_reference(&mut self, from: usize, to: usize) {
216 if let Some(refs) = self.reference_graph.get_mut(&from) {
217 refs.remove(&to);
218 }
219 if let Some(refs) = self.reverse_references.get_mut(&to) {
220 refs.remove(&from);
221 }
222 }
223
224 pub fn add_root(&mut self, obj: usize) {
226 self.root_references.insert(obj);
227 }
228
229 pub fn remove_root(&mut self, obj: usize) {
231 self.root_references.remove(&obj);
232 }
233
234 pub fn get_reachable_objects(&self) -> HashSet<usize> {
236 let mut reachable = HashSet::new();
237 let mut work_list = VecDeque::new();
238
239 for &root in &self.root_references {
241 reachable.insert(root);
242 work_list.push_back(root);
243 }
244
245 while let Some(obj) = work_list.pop_front() {
247 if let Some(refs) = self.reference_graph.get(&obj) {
248 for &target in refs {
249 if reachable.insert(target) {
250 work_list.push_back(target);
251 }
252 }
253 }
254 }
255
256 reachable
257 }
258
259 pub fn write_barrier(&mut self, source: usize, target: usize) {
261 let entry = WriteBarrierEntry {
262 source,
263 target,
264 timestamp: Instant::now(),
265 };
266 self.write_barrier_log.push_back(entry);
267 }
268}
269
270pub struct GCScheduler {
287 #[allow(dead_code)]
289 scheduled_tasks: VecDeque<GCTask>,
290 #[allow(dead_code)]
292 current_task: Option<GCTask>,
293 timing_state: GCTimingState,
295 trigger_conditions: Vec<GCTrigger>,
297}
298
299#[derive(Debug, Clone)]
301pub struct GCTask {
302 pub id: u64,
303 pub algorithm: GCAlgorithm,
304 pub priority: GCPriority,
305 pub target_region: Option<usize>,
306 pub estimated_duration: Duration,
307 pub created_at: Instant,
308 pub deadline: Option<Instant>,
309}
310
311#[derive(Debug, Clone, PartialEq, Ord, PartialOrd, Eq)]
313pub enum GCPriority {
314 Low,
315 Normal,
316 High,
317 Critical,
318}
319
320#[derive(Debug, Clone)]
322pub struct GCTimingState {
323 pub last_young_gc: Option<Instant>,
324 pub last_old_gc: Option<Instant>,
325 pub gc_frequency: f64,
326 pub allocation_rate: f64,
327 pub memory_pressure: f64,
328}
329
330#[derive(Debug, Clone)]
332pub enum GCTrigger {
333 MemoryThreshold(f64),
334 TimeInterval(Duration),
335 AllocationCount(u64),
336 ExplicitRequest,
337 MemoryPressure,
338}
339
340pub trait GarbageCollector: Send + Sync {
342 fn name(&self) -> &str;
343 fn can_collect(&self, region: &MemoryRegion) -> bool;
344 fn estimate_collection_time(&self, region: &MemoryRegion) -> Duration;
345 fn collect(
346 &mut self,
347 region: &mut MemoryRegion,
348 tracker: &mut ReferenceTracker,
349 ) -> Result<GCResult, GCError>;
350 fn get_statistics(&self) -> GCCollectorStats;
351 fn configure(&mut self, config: &GCConfig);
352}
353
354#[derive(Debug, Clone)]
356pub struct GCResult {
357 pub bytes_collected: usize,
358 pub objects_collected: u32,
359 pub collection_time: Duration,
360 pub algorithm_used: GCAlgorithm,
361 pub regions_collected: Vec<usize>,
362 pub promotion_count: u32,
363 pub compaction_performed: bool,
364 pub efficiency_score: f64,
365}
366
367#[derive(Debug, Clone, Default)]
369pub struct GCCollectorStats {
370 pub collections: u64,
371 pub total_time: Duration,
372 pub total_bytes_collected: u64,
373 pub total_objects_collected: u64,
374 pub average_efficiency: f64,
375 pub success_rate: f64,
376}
377
378pub struct MarkSweepCollector {
380 stats: GCCollectorStats,
381 config: MarkSweepConfig,
382}
383
384#[derive(Debug, Clone)]
386pub struct MarkSweepConfig {
387 pub enable_compaction: bool,
388 pub mark_threshold: f64,
389 pub sweep_threshold: f64,
390 pub enable_parallel_marking: bool,
391 pub enable_parallel_sweeping: bool,
392}
393
394impl Default for MarkSweepConfig {
395 fn default() -> Self {
396 Self {
397 enable_compaction: true,
398 mark_threshold: 0.7,
399 sweep_threshold: 0.5,
400 enable_parallel_marking: true,
401 enable_parallel_sweeping: true,
402 }
403 }
404}
405
406impl MarkSweepCollector {
407 pub fn new(config: MarkSweepConfig) -> Self {
408 Self {
409 stats: GCCollectorStats::default(),
410 config,
411 }
412 }
413
414 fn mark_phase(&self, region: &mut MemoryRegion, tracker: &ReferenceTracker) {
420 let reachable = tracker.get_reachable_objects();
421
422 for (addr, obj) in region.objects.iter_mut() {
424 obj.marked = reachable.contains(addr);
425 }
426 }
427
428 fn sweep_phase(&self, region: &mut MemoryRegion) -> (usize, u32) {
429 let mut bytes_collected = 0;
430 let mut objects_collected = 0;
431 let mut objects_to_remove = Vec::new();
432
433 for (addr, obj) in ®ion.objects {
434 if !obj.marked {
435 bytes_collected += obj.size;
436 objects_collected += 1;
437 objects_to_remove.push(*addr);
438 }
439 }
440
441 for addr in objects_to_remove {
443 region.objects.remove(&addr);
444 }
445
446 for obj in region.objects.values_mut() {
448 obj.marked = false;
449 }
450
451 (bytes_collected, objects_collected)
452 }
453}
454
455impl GarbageCollector for MarkSweepCollector {
456 fn name(&self) -> &str {
457 "MarkSweep"
458 }
459
460 fn can_collect(&self, region: &MemoryRegion) -> bool {
461 !region.objects.is_empty() && region.utilization < self.config.mark_threshold
462 }
463
464 fn estimate_collection_time(&self, region: &MemoryRegion) -> Duration {
465 let object_count = region.objects.len();
466 let base_time = Duration::from_micros((object_count * 10) as u64);
467
468 if self.config.enable_compaction {
469 base_time + Duration::from_micros((object_count * 5) as u64)
470 } else {
471 base_time
472 }
473 }
474
475 fn collect(
476 &mut self,
477 region: &mut MemoryRegion,
478 tracker: &mut ReferenceTracker,
479 ) -> Result<GCResult, GCError> {
480 let start_time = Instant::now();
481
482 self.mark_phase(region, tracker);
484
485 let (bytes_collected, objects_collected) = self.sweep_phase(region);
487
488 let collection_time = start_time.elapsed();
489
490 self.stats.collections += 1;
492 self.stats.total_time += collection_time;
493 self.stats.total_bytes_collected += bytes_collected as u64;
494 self.stats.total_objects_collected += objects_collected as u64;
495
496 let efficiency = if collection_time.as_millis() > 0 {
497 bytes_collected as f64 / collection_time.as_millis() as f64
498 } else {
499 0.0
500 };
501
502 self.stats.average_efficiency =
503 (self.stats.average_efficiency * (self.stats.collections - 1) as f64 + efficiency)
504 / self.stats.collections as f64;
505 self.stats.success_rate = 1.0; Ok(GCResult {
508 bytes_collected,
509 objects_collected,
510 collection_time,
511 algorithm_used: GCAlgorithm::MarkSweep,
512 regions_collected: vec![region.base_addr],
513 promotion_count: 0,
514 compaction_performed: self.config.enable_compaction,
515 efficiency_score: efficiency,
516 })
517 }
518
519 fn get_statistics(&self) -> GCCollectorStats {
520 self.stats.clone()
521 }
522
523 fn configure(&mut self, config: &GCConfig) {
524 self.config.enable_parallel_marking = config.parallel_gc;
526 self.config.enable_parallel_sweeping = config.parallel_gc;
527 }
528}
529
530pub struct GenerationalCollector {
532 stats: GCCollectorStats,
533 config: GenerationalConfig,
534 young_gen_collector: Box<dyn GarbageCollector>,
535 old_gen_collector: Box<dyn GarbageCollector>,
536}
537
538#[derive(Debug, Clone)]
540pub struct GenerationalConfig {
541 pub young_gen_threshold: usize,
542 pub promotion_age: u32,
543 pub minor_gc_frequency: u32,
544 pub major_gc_threshold: f64,
545 pub enable_remembered_set: bool,
546}
547
548impl Default for GenerationalConfig {
549 fn default() -> Self {
550 Self {
551 young_gen_threshold: 1024 * 1024, promotion_age: 3,
553 minor_gc_frequency: 10,
554 major_gc_threshold: 0.8,
555 enable_remembered_set: true,
556 }
557 }
558}
559
560impl GenerationalCollector {
561 pub fn new(config: GenerationalConfig) -> Self {
562 let young_collector = Box::new(MarkSweepCollector::new(MarkSweepConfig::default()));
563 let old_collector = Box::new(MarkSweepCollector::new(MarkSweepConfig {
564 enable_compaction: true,
565 ..MarkSweepConfig::default()
566 }));
567
568 Self {
569 stats: GCCollectorStats::default(),
570 config,
571 young_gen_collector: young_collector,
572 old_gen_collector: old_collector,
573 }
574 }
575
576 fn should_promote(&self, obj: &ObjectMetadata) -> bool {
577 obj.age >= self.config.promotion_age
578 }
579
580 fn promote_objects(&self, region: &mut MemoryRegion) -> u32 {
581 let mut promoted = 0;
582
583 for obj in region.objects.values_mut() {
584 if self.should_promote(obj) && region.generation == 0 {
585 promoted += 1;
586 }
588 }
589
590 promoted
591 }
592}
593
594impl GarbageCollector for GenerationalCollector {
595 fn name(&self) -> &str {
596 "Generational"
597 }
598
599 fn can_collect(&self, region: &MemoryRegion) -> bool {
600 !region.objects.is_empty()
601 }
602
603 fn estimate_collection_time(&self, region: &MemoryRegion) -> Duration {
604 if region.generation == 0 {
605 self.young_gen_collector.estimate_collection_time(region)
606 } else {
607 self.old_gen_collector.estimate_collection_time(region)
608 }
609 }
610
611 fn collect(
612 &mut self,
613 region: &mut MemoryRegion,
614 tracker: &mut ReferenceTracker,
615 ) -> Result<GCResult, GCError> {
616 let start_time = Instant::now();
617
618 let result = if region.generation == 0 {
619 self.young_gen_collector.collect(region, tracker)?
621 } else {
622 self.old_gen_collector.collect(region, tracker)?
624 };
625
626 let promotion_count = if region.generation == 0 {
628 self.promote_objects(region)
629 } else {
630 0
631 };
632
633 for obj in region.objects.values_mut() {
635 obj.age += 1;
636 }
637
638 let collection_time = start_time.elapsed();
639
640 self.stats.collections += 1;
642 self.stats.total_time += collection_time;
643 self.stats.total_bytes_collected += result.bytes_collected as u64;
644 self.stats.total_objects_collected += result.objects_collected as u64;
645
646 Ok(GCResult {
647 promotion_count,
648 ..result
649 })
650 }
651
652 fn get_statistics(&self) -> GCCollectorStats {
653 self.stats.clone()
654 }
655
656 fn configure(&mut self, config: &GCConfig) {
657 self.young_gen_collector.configure(config);
658 self.old_gen_collector.configure(config);
659 }
660}
661
662pub struct IncrementalCollector {
664 stats: GCCollectorStats,
665 config: IncrementalConfig,
666 current_phase: IncrementalPhase,
667 work_queue: VecDeque<IncrementalWork>,
668}
669
670#[derive(Debug, Clone)]
672pub struct IncrementalConfig {
673 pub time_slice: Duration,
674 pub work_unit_size: usize,
675 pub pause_threshold: Duration,
676 pub enable_write_barriers: bool,
677}
678
679impl Default for IncrementalConfig {
680 fn default() -> Self {
681 Self {
682 time_slice: Duration::from_millis(2),
683 work_unit_size: 100,
684 pause_threshold: Duration::from_millis(5),
685 enable_write_barriers: true,
686 }
687 }
688}
689
690#[derive(Debug, Clone, PartialEq)]
692pub enum IncrementalPhase {
693 Idle,
694 Marking,
695 Sweeping,
696 Compacting,
697 Finalizing,
698}
699
700#[derive(Debug, Clone)]
702pub struct IncrementalWork {
703 pub phase: IncrementalPhase,
704 pub region_addr: usize,
705 pub object_range: (usize, usize),
706 pub estimated_time: Duration,
707}
708
709impl IncrementalCollector {
710 pub fn new(config: IncrementalConfig) -> Self {
711 Self {
712 stats: GCCollectorStats::default(),
713 config,
714 current_phase: IncrementalPhase::Idle,
715 work_queue: VecDeque::new(),
716 }
717 }
718
719 fn schedule_incremental_work(&mut self, region: &MemoryRegion) {
720 let mut object_addrs: Vec<usize> = region.objects.keys().copied().collect();
721 object_addrs.sort_unstable();
725 let chunk_size = self.config.work_unit_size;
726
727 for chunk in object_addrs.chunks(chunk_size) {
734 if !chunk.is_empty() {
735 self.work_queue.push_back(IncrementalWork {
736 phase: IncrementalPhase::Marking,
737 region_addr: region.base_addr,
738 object_range: (chunk[0], chunk[chunk.len() - 1]),
739 estimated_time: Duration::from_micros(chunk.len() as u64 * 10),
740 });
741 }
742 }
743 for chunk in object_addrs.chunks(chunk_size) {
744 if !chunk.is_empty() {
745 self.work_queue.push_back(IncrementalWork {
746 phase: IncrementalPhase::Sweeping,
747 region_addr: region.base_addr,
748 object_range: (chunk[0], chunk[chunk.len() - 1]),
749 estimated_time: Duration::from_micros(chunk.len() as u64 * 10),
750 });
751 }
752 }
753 }
754
755 fn perform_incremental_work(
756 &mut self,
757 region: &mut MemoryRegion,
758 tracker: &mut ReferenceTracker,
759 ) -> Option<GCResult> {
760 let time_budget = self.config.time_slice;
761 let start_time = Instant::now();
762 let mut work_done = false;
763 let mut bytes_collected = 0usize;
764 let mut objects_collected = 0u32;
765
766 while start_time.elapsed() < time_budget {
767 if let Some(work) = self.work_queue.pop_front() {
768 self.current_phase = work.phase.clone();
769 match work.phase {
770 IncrementalPhase::Marking => {
771 let reachable = tracker.get_reachable_objects();
773 for addr in work.object_range.0..=work.object_range.1 {
774 if let Some(obj) = region.objects.get_mut(&addr) {
775 obj.marked = reachable.contains(&addr);
776 }
777 }
778 work_done = true;
779 }
780 IncrementalPhase::Sweeping => {
781 for addr in work.object_range.0..=work.object_range.1 {
783 if let Some(obj) = region.objects.get(&addr) {
784 if !obj.marked {
785 bytes_collected += obj.size;
786 objects_collected += 1;
787 region.objects.remove(&addr);
788 }
789 }
790 }
791 work_done = true;
792 }
793 _ => {}
794 }
795 } else {
796 break;
797 }
798 }
799
800 if work_done && self.work_queue.is_empty() {
801 self.current_phase = IncrementalPhase::Idle;
803 Some(GCResult {
804 bytes_collected,
805 objects_collected,
806 collection_time: start_time.elapsed(),
807 algorithm_used: GCAlgorithm::Incremental,
808 regions_collected: vec![region.base_addr],
809 promotion_count: 0,
810 compaction_performed: false,
811 efficiency_score: 0.0,
812 })
813 } else {
814 None
815 }
816 }
817
818 pub fn current_phase(&self) -> &IncrementalPhase {
821 &self.current_phase
822 }
823}
824
825impl GarbageCollector for IncrementalCollector {
826 fn name(&self) -> &str {
827 "Incremental"
828 }
829
830 fn can_collect(&self, region: &MemoryRegion) -> bool {
831 !region.objects.is_empty()
832 }
833
834 fn estimate_collection_time(&self, region: &MemoryRegion) -> Duration {
835 let object_count = region.objects.len();
836 Duration::from_millis(
837 (object_count / self.config.work_unit_size) as u64
838 * self.config.time_slice.as_millis() as u64,
839 )
840 }
841
842 fn collect(
843 &mut self,
844 region: &mut MemoryRegion,
845 tracker: &mut ReferenceTracker,
846 ) -> Result<GCResult, GCError> {
847 if self.work_queue.is_empty() {
848 self.schedule_incremental_work(region);
849 }
850
851 if let Some(result) = self.perform_incremental_work(region, tracker) {
852 self.stats.collections += 1;
853 self.stats.total_time += result.collection_time;
854 Ok(result)
855 } else {
856 Err(GCError::CollectionIncomplete(
857 "Incremental collection in progress".to_string(),
858 ))
859 }
860 }
861
862 fn get_statistics(&self) -> GCCollectorStats {
863 self.stats.clone()
864 }
865
866 fn configure(&mut self, config: &GCConfig) {
867 self.config.time_slice = config.max_pause_time;
868 }
869}
870
871#[derive(Debug, Clone)]
873pub struct GCPerformance {
874 pub timestamp: Instant,
875 pub algorithm: GCAlgorithm,
876 pub collection_time: Duration,
877 pub bytes_collected: usize,
878 pub objects_collected: u32,
879 pub regions_affected: usize,
880 pub efficiency_score: f64,
881 pub memory_before: usize,
882 pub memory_after: usize,
883}
884
885impl GarbageCollectionEngine {
886 pub fn new(config: GCConfig) -> Self {
887 let mut collectors: Vec<Box<dyn GarbageCollector>> = Vec::new();
888
889 collectors.push(Box::new(
891 MarkSweepCollector::new(MarkSweepConfig::default()),
892 ));
893
894 if config.enable_generational {
895 collectors.push(Box::new(GenerationalCollector::new(
896 GenerationalConfig::default(),
897 )));
898 }
899
900 if config.enable_incremental {
901 collectors.push(Box::new(IncrementalCollector::new(
902 IncrementalConfig::default(),
903 )));
904 }
905
906 let gc_threshold = config.gc_threshold;
907 Self {
908 config,
909 stats: GCStats::default(),
910 collectors,
911 memory_regions: HashMap::new(),
912 reference_tracker: ReferenceTracker::new(),
913 scheduler: GCScheduler {
914 scheduled_tasks: VecDeque::new(),
915 current_task: None,
916 timing_state: GCTimingState {
917 last_young_gc: None,
918 last_old_gc: None,
919 gc_frequency: 0.0,
920 allocation_rate: 0.0,
921 memory_pressure: 0.0,
922 },
923 trigger_conditions: vec![
924 GCTrigger::MemoryThreshold(gc_threshold),
925 GCTrigger::TimeInterval(Duration::from_secs(30)),
926 ],
927 },
928 performance_history: VecDeque::with_capacity(1000),
929 }
930 }
931
932 pub fn register_region(&mut self, base_addr: usize, size: usize, generation: u32) {
934 let region = MemoryRegion {
935 base_addr,
936 size,
937 generation,
938 objects: HashMap::new(),
939 free_bitmap: vec![0; (size / 64) + 1],
940 last_collection: None,
941 collection_count: 0,
942 utilization: 0.0,
943 };
944
945 self.memory_regions.insert(base_addr, region);
946 }
947
948 pub fn track_object(
950 &mut self,
951 region_addr: usize,
952 obj_addr: usize,
953 size: usize,
954 type_id: u32,
955 ) -> Result<(), GCError> {
956 let region = self
957 .memory_regions
958 .get_mut(®ion_addr)
959 .ok_or_else(|| GCError::RegionNotFound("Region not registered".to_string()))?;
960
961 let metadata = ObjectMetadata {
962 address: obj_addr,
963 size,
964 type_id,
965 ref_count: 0,
966 marked: false,
967 age: 0,
968 last_access: Some(Instant::now()),
969 references: Vec::new(),
970 };
971
972 region.objects.insert(obj_addr, metadata);
973 Ok(())
974 }
975
976 pub fn should_collect(&mut self) -> bool {
978 if !self.config.auto_gc {
979 return false;
980 }
981
982 for trigger in &self.scheduler.trigger_conditions {
983 match trigger {
984 GCTrigger::MemoryThreshold(threshold) => {
985 let total_used = self.calculate_total_memory_usage();
986 let total_size = self.calculate_total_memory_size();
987 if total_size > 0 && (total_used as f64 / total_size as f64) > *threshold {
988 return true;
989 }
990 }
991 GCTrigger::TimeInterval(interval) => {
992 if let Some(last_gc) = self.stats.last_gc_time {
993 if last_gc.elapsed() > *interval {
994 return true;
995 }
996 } else {
997 return true; }
999 }
1000 GCTrigger::MemoryPressure if self.scheduler.timing_state.memory_pressure > 0.8 => {
1001 return true;
1002 }
1003 _ => {}
1004 }
1005 }
1006
1007 false
1008 }
1009
1010 pub fn collect(&mut self) -> Result<Vec<GCResult>, GCError> {
1012 let mut results = Vec::new();
1013
1014 let collector_indices: Result<Vec<(usize, usize)>, GCError> = self
1016 .memory_regions
1017 .iter()
1018 .map(|(addr, region)| {
1019 let collector_index = self.select_collector(region)?;
1020 Ok((*addr, collector_index))
1021 })
1022 .collect();
1023
1024 let collector_indices = collector_indices?;
1025
1026 for (region_addr, collector_index) in collector_indices {
1028 let utilization = {
1030 let region = self
1031 .memory_regions
1032 .get(®ion_addr)
1033 .ok_or_else(|| GCError::InvalidRegion("Region not found".to_string()))?;
1034 self.calculate_region_utilization(region)
1035 };
1036
1037 let region = self
1038 .memory_regions
1039 .get_mut(®ion_addr)
1040 .ok_or_else(|| GCError::InvalidRegion("Region not found".to_string()))?;
1041
1042 let collector = &mut self.collectors[collector_index];
1043
1044 let result = collector.collect(region, &mut self.reference_tracker)?;
1046
1047 region.last_collection = Some(Instant::now());
1049 region.collection_count += 1;
1050 region.utilization = utilization;
1051
1052 self.stats.total_cycles += 1;
1054 self.stats.total_gc_time += result.collection_time;
1055 self.stats.total_bytes_collected += result.bytes_collected as u64;
1056 self.stats.total_objects_collected += result.objects_collected as u64;
1057
1058 let pause_time = result.collection_time;
1060 if pause_time > self.stats.max_pause_time {
1061 self.stats.max_pause_time = pause_time;
1062 }
1063
1064 let total_time = self.stats.average_pause_time.as_nanos() as u64
1065 * (self.stats.total_cycles - 1)
1066 + pause_time.as_nanos() as u64;
1067 self.stats.average_pause_time =
1068 Duration::from_nanos(total_time / self.stats.total_cycles);
1069
1070 let performance = GCPerformance {
1072 timestamp: Instant::now(),
1073 algorithm: result.algorithm_used.clone(),
1074 collection_time: result.collection_time,
1075 bytes_collected: result.bytes_collected,
1076 objects_collected: result.objects_collected,
1077 regions_affected: 1,
1078 efficiency_score: result.efficiency_score,
1079 memory_before: region.size, memory_after: region.size - result.bytes_collected,
1081 };
1082
1083 self.performance_history.push_back(performance);
1084 if self.performance_history.len() > 1000 {
1085 self.performance_history.pop_front();
1086 }
1087
1088 results.push(result);
1089 }
1090
1091 self.stats.last_gc_time = Some(Instant::now());
1092 Ok(results)
1093 }
1094
1095 fn select_collector(&self, region: &MemoryRegion) -> Result<usize, GCError> {
1096 for (i, collector) in self.collectors.iter().enumerate() {
1097 if collector.can_collect(region) {
1098 return Ok(i);
1099 }
1100 }
1101
1102 Err(GCError::NoSuitableCollector(
1103 "No collector available for region".to_string(),
1104 ))
1105 }
1106
1107 fn calculate_total_memory_usage(&self) -> usize {
1108 self.memory_regions
1109 .values()
1110 .map(|region| region.objects.values().map(|obj| obj.size).sum::<usize>())
1111 .sum()
1112 }
1113
1114 fn calculate_total_memory_size(&self) -> usize {
1115 self.memory_regions.values().map(|region| region.size).sum()
1116 }
1117
1118 fn calculate_region_utilization(&self, region: &MemoryRegion) -> f64 {
1119 let used_size: usize = region.objects.values().map(|obj| obj.size).sum();
1120 used_size as f64 / region.size as f64
1121 }
1122
1123 pub fn get_stats(&self) -> &GCStats {
1125 &self.stats
1126 }
1127
1128 pub fn get_performance_history(&self) -> &VecDeque<GCPerformance> {
1130 &self.performance_history
1131 }
1132
1133 pub fn get_collector_info(&self) -> Vec<(String, GCCollectorStats)> {
1135 self.collectors
1136 .iter()
1137 .map(|collector| (collector.name().to_string(), collector.get_statistics()))
1138 .collect()
1139 }
1140
1141 pub fn force_collect_region(&mut self, region_addr: usize) -> Result<GCResult, GCError> {
1143 let collector_index = {
1145 let region = self
1146 .memory_regions
1147 .get(®ion_addr)
1148 .ok_or_else(|| GCError::RegionNotFound("Region not found".to_string()))?;
1149 self.select_collector(region)?
1150 };
1151
1152 let region = self
1154 .memory_regions
1155 .get_mut(®ion_addr)
1156 .ok_or_else(|| GCError::RegionNotFound("Region not found".to_string()))?;
1157
1158 let collector = &mut self.collectors[collector_index];
1159 collector.collect(region, &mut self.reference_tracker)
1160 }
1161
1162 pub fn add_reference(&mut self, from: usize, to: usize) {
1164 self.reference_tracker.add_reference(from, to);
1165 }
1166
1167 pub fn remove_reference(&mut self, from: usize, to: usize) {
1169 self.reference_tracker.remove_reference(from, to);
1170 }
1171
1172 pub fn add_root_reference(&mut self, obj: usize) {
1174 self.reference_tracker.add_root(obj);
1175 }
1176
1177 pub fn remove_root_reference(&mut self, obj: usize) {
1179 self.reference_tracker.remove_root(obj);
1180 }
1181}
1182
1183#[derive(Debug, Clone)]
1185pub enum GCError {
1186 RegionNotFound(String),
1187 ObjectNotFound(String),
1188 CollectionFailed(String),
1189 CollectionIncomplete(String),
1190 NoSuitableCollector(String),
1191 ConfigurationError(String),
1192 InternalError(String),
1193 InvalidRegion(String),
1194}
1195
1196impl std::fmt::Display for GCError {
1197 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1198 match self {
1199 GCError::RegionNotFound(msg) => write!(f, "Region not found: {}", msg),
1200 GCError::ObjectNotFound(msg) => write!(f, "Object not found: {}", msg),
1201 GCError::CollectionFailed(msg) => write!(f, "Collection failed: {}", msg),
1202 GCError::CollectionIncomplete(msg) => write!(f, "Collection incomplete: {}", msg),
1203 GCError::NoSuitableCollector(msg) => write!(f, "No suitable collector: {}", msg),
1204 GCError::ConfigurationError(msg) => write!(f, "Configuration error: {}", msg),
1205 GCError::InternalError(msg) => write!(f, "Internal error: {}", msg),
1206 GCError::InvalidRegion(msg) => write!(f, "Invalid region: {}", msg),
1207 }
1208 }
1209}
1210
1211impl std::error::Error for GCError {}
1212
1213pub struct ThreadSafeGCEngine {
1215 engine: Arc<RwLock<GarbageCollectionEngine>>,
1216}
1217
1218impl ThreadSafeGCEngine {
1219 pub fn new(config: GCConfig) -> Self {
1220 Self {
1221 engine: Arc::new(RwLock::new(GarbageCollectionEngine::new(config))),
1222 }
1223 }
1224
1225 pub fn should_collect(&self) -> bool {
1226 let mut engine = self.engine.write().unwrap_or_else(|e| e.into_inner());
1227 engine.should_collect()
1228 }
1229
1230 pub fn collect(&self) -> Result<Vec<GCResult>, GCError> {
1231 let mut engine = self.engine.write().unwrap_or_else(|e| e.into_inner());
1232 engine.collect()
1233 }
1234
1235 pub fn get_stats(&self) -> GCStats {
1236 let engine = self.engine.read().unwrap_or_else(|e| e.into_inner());
1237 engine.get_stats().clone()
1238 }
1239
1240 pub fn track_object(
1241 &self,
1242 region_addr: usize,
1243 obj_addr: usize,
1244 size: usize,
1245 type_id: u32,
1246 ) -> Result<(), GCError> {
1247 let mut engine = self.engine.write().unwrap_or_else(|e| e.into_inner());
1248 engine.track_object(region_addr, obj_addr, size, type_id)
1249 }
1250}
1251
1252#[cfg(test)]
1253mod tests {
1254 use super::*;
1255
1256 #[test]
1257 fn test_gc_engine_creation() {
1258 let config = GCConfig::default();
1259 let engine = GarbageCollectionEngine::new(config);
1260 assert!(!engine.collectors.is_empty());
1261 }
1262
1263 #[test]
1264 fn test_region_registration() {
1265 let config = GCConfig::default();
1266 let mut engine = GarbageCollectionEngine::new(config);
1267
1268 engine.register_region(0x1000, 4096, 0);
1269 assert!(engine.memory_regions.contains_key(&0x1000));
1270 }
1271
1272 #[test]
1273 fn test_object_tracking() {
1274 let config = GCConfig::default();
1275 let mut engine = GarbageCollectionEngine::new(config);
1276
1277 engine.register_region(0x1000, 4096, 0);
1278 let result = engine.track_object(0x1000, 0x1100, 64, 1);
1279 assert!(result.is_ok());
1280 }
1281
1282 #[test]
1283 fn test_reference_tracking() {
1284 let mut tracker = ReferenceTracker::new();
1285
1286 tracker.add_root(100);
1287 tracker.add_reference(100, 200);
1288 tracker.add_reference(200, 300);
1289
1290 let reachable = tracker.get_reachable_objects();
1291 assert!(reachable.contains(&100));
1292 assert!(reachable.contains(&200));
1293 assert!(reachable.contains(&300));
1294 }
1295
1296 #[test]
1297 fn test_mark_sweep_collector() {
1298 let config = MarkSweepConfig::default();
1299 let collector = MarkSweepCollector::new(config);
1300
1301 assert_eq!(collector.name(), "MarkSweep");
1302 }
1303
1304 #[test]
1305 fn test_generational_collector() {
1306 let config = GenerationalConfig::default();
1307 let collector = GenerationalCollector::new(config);
1308
1309 assert_eq!(collector.name(), "Generational");
1310 }
1311
1312 #[test]
1313 fn test_incremental_collector() {
1314 let config = IncrementalConfig::default();
1315 let collector = IncrementalCollector::new(config);
1316
1317 assert_eq!(collector.name(), "Incremental");
1318 assert_eq!(*collector.current_phase(), IncrementalPhase::Idle);
1319 }
1320
1321 #[test]
1322 fn test_incremental_collector_marks_then_sweeps_and_returns_to_idle() {
1323 let config = IncrementalConfig::default();
1324 let mut collector = IncrementalCollector::new(config);
1325 let mut tracker = ReferenceTracker::new();
1326
1327 tracker.add_root(100);
1329
1330 let mut objects = HashMap::new();
1331 for addr in [100usize, 200, 300] {
1332 objects.insert(
1333 addr,
1334 ObjectMetadata {
1335 address: addr,
1336 size: 64,
1337 type_id: 0,
1338 ref_count: 0,
1339 marked: false,
1340 age: 0,
1341 last_access: Some(Instant::now()),
1342 references: Vec::new(),
1343 },
1344 );
1345 }
1346 let mut region = MemoryRegion {
1347 base_addr: 0x1000,
1348 size: 4096,
1349 generation: 0,
1350 objects,
1351 free_bitmap: Vec::new(),
1352 last_collection: None,
1353 collection_count: 0,
1354 utilization: 0.0,
1355 };
1356
1357 let mut result = None;
1362 for _ in 0..100 {
1363 match collector.collect(&mut region, &mut tracker) {
1364 Ok(r) => {
1365 result = Some(r);
1366 break;
1367 }
1368 Err(GCError::CollectionIncomplete(_)) => continue,
1369 Err(e) => panic!("unexpected GC error: {e:?}"),
1370 }
1371 }
1372 let result = result.expect("incremental collection should complete within 100 slices");
1373
1374 assert_eq!(result.objects_collected, 2);
1377 assert_eq!(result.bytes_collected, 128);
1378 assert!(region.objects.contains_key(&100));
1379 assert!(!region.objects.contains_key(&200));
1380 assert!(!region.objects.contains_key(&300));
1381 assert_eq!(*collector.current_phase(), IncrementalPhase::Idle);
1382 }
1383
1384 #[test]
1385 fn test_thread_safe_gc_engine() {
1386 let config = GCConfig::default();
1387 let engine = ThreadSafeGCEngine::new(config);
1388
1389 let stats = engine.get_stats();
1390 assert_eq!(stats.total_cycles, 0);
1391 }
1392}