pub struct GcHeap { /* private fields */ }Implementations§
Source§impl GcHeap
impl GcHeap
pub const DUMMY_DISPOSE_CALLBACK: fn(&GcHeap, &GcHead)
Sourcepub fn new(registry: &'static GcTypeRegistry) -> Self
pub fn new(registry: &'static GcTypeRegistry) -> Self
Create a new garbage collection heap with an explicit GC type registry.
The heap starts with no partitions. Use create_partition
to add partitions as needed.
Examples found in repository?
More examples
56fn main() -> GcResult<()> {
57 let mut heap = GcHeap::new(&GC_TYPE_REGISTRY);
58 let partition = heap.create_partition(64 * 1024, 16 * 1024);
59 let stack_id = heap.acquire_scope_stack(partition);
60
61 let static_ref = alloc_static(&mut heap, stack_id, 10)?;
62 let other_ref = alloc_other(&mut heap, stack_id, 20)?;
63
64 println!(
65 "Static node value: {}",
66 unsafe { static_ref.as_ref() }._value
67 );
68 println!("Other node value: {}", unsafe { other_ref.as_ref() }._value);
69
70 heap.release_scope_stack(stack_id);
71
72 println!("gc_node_usage example verified");
73
74 Ok(())
75}38fn benchmark_object_sizes() {
39 let sizes = [10, 100, 500, 1000, 5000];
40
41 for &size in &sizes {
42 println!("\nTest object count: {}", size);
43
44 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
45 let partition = context.create_partition(64 * 1024, 16 * 1024);
46
47 // Measure allocation performance
48 let alloc_start = Instant::now();
49 let mut objects = Vec::new();
50 for _i in 0..size {
51 let node = unsafe {
52 context.alloc_raw(
53 partition,
54 SimpleNode {
55 _data: vec![0u8; 100],
56 },
57 )
58 } // Each node 100 bytes
59 .unwrap();
60 objects.push(node);
61 }
62 let alloc_duration = alloc_start.elapsed();
63
64 println!(" Allocated {} objects in: {:?}", size, alloc_duration);
65 println!(
66 " Average allocation time per object: {:?}",
67 alloc_duration / size as u32
68 );
69
70 // Measure GC performance (all objects can be collected)
71 let gc_start = Instant::now();
72 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
73 let gc_duration = gc_start.elapsed();
74
75 println!(" GC回收 {} 字节耗时: {:?}", freed, gc_duration);
76 println!(
77 " Average collection time per byte: {:?}",
78 if freed > 0 {
79 gc_duration / freed as u32
80 } else {
81 Duration::from_nanos(0)
82 }
83 );
84 }
85}
86
87/// Test GC performance of complex object graphs
88fn benchmark_complex_graphs() {
89 let sizes = [100, 500, 1000];
90
91 for &size in &sizes {
92 println!("\nTest complex object graph size: {} nodes", size);
93
94 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
95 let partition = context.create_partition(64 * 1024, 16 * 1024);
96
97 // Create complex object graph
98 let graph_start = Instant::now();
99 let mut nodes = Vec::new();
100
101 // Create all nodes
102 for _i in 0..size {
103 let node = unsafe {
104 context.alloc_raw(
105 partition,
106 GraphNode {
107 neighbors: Vec::new(),
108 },
109 )
110 }
111 .unwrap();
112 nodes.push(node);
113 }
114
115 // Establish complex dependencies
116 for i in 0..size {
117 {
118 // Each node points to subsequent nodes
119 for j in 1..=5 {
120 if i + j < size {
121 let n = nodes[i + j];
122 unsafe {
123 nodes[i]
124 .with_write_barrier(&mut context, |node| node.neighbors.push(n));
125 }
126 }
127 }
128 // Every 10 nodes form a cycle
129 if i % 10 == 0 && i + 9 < size {
130 let n = nodes[i];
131 unsafe {
132 nodes[i + 9]
133 .with_write_barrier(&mut context, |node| node.neighbors.push(n));
134 }
135 }
136 }
137 }
138 let graph_duration = graph_start.elapsed();
139
140 println!(" Built complex object graph in: {:?}", graph_duration);
141
142 // Measure GC performance
143 let gc_start = Instant::now();
144 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
145 let gc_duration = gc_start.elapsed();
146
147 println!(" GC回收 {} 字节耗时: {:?}", freed, gc_duration);
148 println!(
149 " Object graph complexity: average {} neighbors per node",
150 if size > 0 { (size * 5) / size } else { 0 }
151 );
152 }
153}
154
155/// Test memory usage efficiency
156fn benchmark_memory_efficiency() {
157 println!("\nTesting memory usage efficiency...");
158
159 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
160 context.set_memory_limit(1024 * 1024); // 1MB global limit
161 let partition = context.create_partition(64 * 1024, 16 * 1024);
162
163 // Allocate many small objects
164 let small_objects_count = 1000;
165 let mut small_objects = Vec::new();
166
167 for _i in 0..small_objects_count {
168 let obj = unsafe { context.alloc_raw(partition, SmallData {}) }.unwrap();
169 small_objects.push(obj);
170 }
171
172 if let Some(partition_info) = context.partition(partition) {
173 let used = partition_info.memory_used();
174 let limit = context.memory_limit();
175 let efficiency = if limit > 0 {
176 (used as f64 / limit as f64) * 100.0
177 } else {
178 0.0
179 };
180
181 println!(" After allocating {} small objects:", small_objects_count);
182 println!(
183 " Memory usage: {}/{} bytes ({:.1}%)",
184 used, limit, efficiency
185 );
186 println!(
187 " Average overhead per object: {} bytes",
188 if small_objects_count > 0 {
189 used / small_objects_count
190 } else {
191 0
192 }
193 );
194 }
195
196 // Collect all objects
197 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
198 println!(" Collected all objects, freed {} bytes", freed);
199
200 // Verify complete memory collection
201 if let Some(partition_info) = context.partition(partition) {
202 let used_after = partition_info.memory_used();
203 println!(" Memory usage after collection: {} bytes", used_after);
204 println!(
205 " Memory collection rate: {:.1}%",
206 if freed > 0 {
207 (freed as f64 / (freed + used_after) as f64) * 100.0
208 } else {
209 0.0
210 }
211 );
212 }
213}
214
215/// Test automatic GC threshold performance
216fn benchmark_auto_gc_threshold() {
217 println!("\nTesting automatic GC threshold performance...");
218
219 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
220 context.set_memory_limit(2048); // 2KB global limit
221 let partition = context.create_partition(64 * 1024, 16 * 1024);
222
223 // Set automatic GC threshold to 1.5KB
224 context.set_gc_threshold(1500);
225
226 // Allocate objects until automatic GC is triggered
227 let mut allocated_bytes = 0;
228 let mut object_count = 0;
229
230 println!(" Allocating objects until automatic GC is triggered...");
231
232 for _i in 0..100 {
233 // Try at most 100 times
234 // Allocate objects of about 100 bytes
235 let node = SimpleNode {
236 _data: vec![0u8; 100],
237 };
238 match unsafe { context.alloc_raw(partition, node) } {
239 Ok(_gc_ref) => {
240 allocated_bytes += 100 + std::mem::size_of::<GcRef<SimpleNode>>(); // Estimated size
241 object_count += 1;
242
243 // Check if approaching threshold
244 if let Some(partition_info) = context.partition(partition)
245 && partition_info.memory_used() >= 1500
246 {
247 println!(
248 " Reached automatic GC threshold, allocated {} objects",
249 object_count
250 );
251 println!(" Estimated allocated memory: {} bytes", allocated_bytes);
252 println!(
253 " Actual memory usage: {} bytes",
254 partition_info.memory_used()
255 );
256 break;
257 }
258 }
259 Err(_) => {
260 println!(" Allocation failed, automatic GC may have been triggered");
261 break;
262 }
263 }
264 }
265
266 // Manually trigger GC to see effect
267 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
268 println!(" Manual GC freed {} bytes", freed);
269}34fn demonstrate_out_of_memory() -> GcResult<()> {
35 println!("1. Create limited memory partition...");
36
37 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
38 context.set_memory_limit(2048); // 2KB global limit
39 let partition_id = context.create_partition(64 * 1024, 16 * 1024);
40
41 // Allocate first large object (1KB + header)
42 println!("2. Allocate first large object...");
43 let gc1: GcRef<LargeData> =
44 match unsafe { context.alloc_raw(partition_id, LargeData { data: [0; 1024] }) } {
45 Ok(gc_ref) => {
46 println!(" ✓ Successfully allocated first object (1KB)");
47 gc_ref
48 }
49 Err((error, _)) => {
50 println!(" ✗ First object allocation failed: {:?}", error);
51 return Ok(());
52 }
53 };
54
55 // Allocate second large object (1KB + header) - should exceed 2KB limit
56 println!("3. Try to allocate second large object...");
57 match unsafe { context.alloc_raw(partition_id, LargeData { data: [0; 1024] }) } {
58 Err((GcError::PartitionFull, _)) => {
59 println!(" ✓ Correctly detected partition full error");
60 }
61 Ok(_) => {
62 println!(" ✗ Expected partition full error, but allocation succeeded");
63 return Ok(());
64 }
65 Err((other_error, _)) => {
66 println!(
67 " ✗ Expected partition full error, but got: {:?}",
68 other_error
69 );
70 return Ok(());
71 }
72 }
73
74 // Clean up - through garbage collection instead of manual release
75 println!(" ✓ Automatic cleanup through GC");
76 context.garbage_collect(partition_id, GcHeap::DUMMY_DISPOSE_CALLBACK);
77
78 Ok(())
79}
80
81/// Demonstrate partition management errors
82fn demonstrate_partition_management_errors() -> GcResult<()> {
83 println!("1. Test non-existent partition operations...");
84
85 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
86 let invalid_partition = gc_lite::GcPartitionId(9999); // Non-existent partition
87
88 // Test allocating objects in non-existent partition
89 match unsafe {
90 context.alloc_raw(
91 invalid_partition,
92 TestData {
93 value: 42,
94 name: "test".to_string(),
95 },
96 )
97 } {
98 Err((GcError::PartitionNotFound, _)) => {
99 println!(" ✓ Allocating objects in non-existent partition returns correct error");
100 }
101 Ok(_) => {
102 println!(" ✗ Expected partition not found error, but allocation succeeded");
103 }
104 Err((other_error, _)) => {
105 println!(
106 " ✗ Expected partition not found error, but got: {:?}",
107 other_error
108 );
109 }
110 }
111
112 // Test getting non-existent partition information
113 let partition_info = context.partition(invalid_partition);
114 assert!(
115 partition_info.is_none(),
116 "Non-existent partition should return None"
117 );
118 println!(" ✓ Getting non-existent partition info returns None");
119
120 // Test removing non-existent partition (remove_partition doesn't return error, just silently fails)
121 context.remove_partition(invalid_partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
122 println!(" ✓ Removing non-existent partition silently fails");
123
124 println!("\n2. Test non-empty partition deletion...");
125 let partition_id = context.create_partition(64 * 1024, 16 * 1024);
126
127 // Allocate objects in partition
128 let obj = unsafe {
129 context.alloc_raw(
130 partition_id,
131 TestData {
132 value: 1,
133 name: "obj".to_string(),
134 },
135 )
136 }
137 .unwrap();
138 let _ = obj;
139
140 // Try to delete non-empty partition (remove_partition will force cleanup)
141 context.remove_partition(partition_id, GcHeap::DUMMY_DISPOSE_CALLBACK);
142 println!(" ✓ Successfully deleted non-empty partition (root objects were force cleaned)");
143
144 Ok(())
145}
146
147/// Demonstrate GC threshold API errors
148fn demonstrate_gc_threshold_errors() -> GcResult<()> {
149 println!("1. Test GC threshold API...");
150
151 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
152 context.set_memory_limit(1024);
153 let _partition_id = context.create_partition(64 * 1024, 16 * 1024);
154
155 // Test default values
156 println!("2. Test default threshold...");
157 assert_eq!(context.gc_threshold(), 0);
158 println!(" ✓ Default threshold is 0, automatic GC disabled");
159
160 // Test setting threshold
161 println!("3. Test setting threshold...");
162 context.set_gc_threshold(512);
163 assert_eq!(context.gc_threshold(), 512);
164 println!(" ✓ Successfully set threshold to 512, automatic GC enabled");
165
166 // Test setting threshold exceeding memory limit
167 println!("4. Test setting threshold exceeding memory limit...");
168 context.set_gc_threshold(2048);
169 // Since threshold exceeds memory limit, will be capped at 0.8x of limit (1024 * 8 / 10 = 819)
170 assert_eq!(context.gc_threshold(), 819);
171 println!(
172 " ✓ Setting threshold exceeding memory limit automatically adjusted to 0.8x of memory limit"
173 );
174
175 // Test disabling automatic GC
176 println!("5. Test disabling automatic GC...");
177 context.set_gc_threshold(0);
178 assert_eq!(context.gc_threshold(), 0);
179 println!(" ✓ Successfully disabled automatic GC, threshold set to 0");
180
181 Ok(())
182}47fn main() -> GcResult<()> {
48 println!("=== Basic usage example of partitioned garbage collection system ===");
49
50 // Create garbage collection context
51 let mut heap = GcHeap::new(&GC_TYPE_REGISTRY);
52
53 println!("Initial state:");
54 println!(" Number of partitions: {}", heap.partition_ids().len());
55
56 // Create two partitions
57 println!("\nCreate partitions:");
58 let partition1 = heap.create_partition(64 * 1024, 16 * 1024);
59 let partition2 = heap.create_partition(64 * 1024, 16 * 1024);
60 println!(" Created partition1: {:?}", partition1);
61 println!(" Created partition2: {:?}", partition2);
62 println!(" Number of partitions: {}", heap.partition_ids().len());
63
64 // Allocate objects in partition1
65 println!("\nAllocate objects in partition1:");
66 let obj1 = unsafe { heap.alloc_raw(partition1, MyString(String::from("Hello"))) }
67 .map_err(|(err, _)| err)?;
68 let obj2 = unsafe { heap.alloc_raw(partition1, MyI32(42)) }.map_err(|(err, _)| err)?;
69 let obj3 = unsafe { heap.alloc_raw(partition1, MyString(String::from("VectorData"))) }
70 .map_err(|(err, _)| err)?;
71
72 println!(" Created string: '{}'", unsafe { obj1.as_ref() });
73 println!(" Created number: {}", unsafe { obj2.as_ref() });
74 println!(" Created string: '{}'", unsafe { obj3.as_ref() });
75
76 // Allocate objects in partition2
77 println!("\nAllocate objects in partition2:");
78 let obj4 = unsafe { heap.alloc_raw(partition2, MyString(String::from("World"))) }
79 .map_err(|(err, _)| err)?;
80 let obj5 = unsafe { heap.alloc_raw(partition2, MyI32(99)) }.map_err(|(err, _)| err)?;
81
82 println!(" Created string: '{}'", unsafe { obj4.as_ref() });
83 println!(" Created number: {}", unsafe { obj5.as_ref() });
84
85 // Display partition status
86 println!("\nPartition status:");
87 for partition_id in heap.partition_ids() {
88 if let Some(partition) = heap.partition(partition_id) {
89 let limit = heap.memory_limit();
90 let usage = if limit > 0 {
91 format!(
92 "{}/{} bytes ({:.1}%)",
93 partition.memory_used(),
94 limit,
95 (partition.memory_used() as f64 / limit as f64) * 100.0
96 )
97 } else {
98 format!("{}/∞ bytes", partition.memory_used())
99 };
100 println!(
101 " {:?}: {} [自动GC: {}]",
102 partition_id,
103 usage,
104 if heap.gc_threshold() > 0 {
105 "Enabled"
106 } else {
107 "Disabled"
108 }
109 );
110 }
111 }
112
113 // Root objects are now implicitly managed by stack variables (e.g., obj1, obj2).
114 // No explicit `set_root` calls are needed for them.
115 println!("\nRoot objects are held by variables:");
116 println!(" Roots: obj1, obj2, obj3, obj4, obj5");
117
118 // Manually trigger garbage collection for partition1
119 println!("\nManually trigger garbage collection for partition1...");
120 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
121 println!(" Collected {} bytes", freed);
122
123 // Verify root objects are still valid
124 println!("\nVerify partition1 root objects are still valid:");
125 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
126 println!(" Object2: {}", unsafe { obj2.as_ref() });
127
128 // Manually trigger garbage collection for partition2
129 println!("\nManually trigger garbage collection for partition2...");
130 let freed = heap.garbage_collect(partition2, GcHeap::DUMMY_DISPOSE_CALLBACK);
131 println!(" Collected {} bytes", freed);
132
133 // Verify partition2 root objects are still valid
134 println!("\nVerify partition2 root objects are still valid:");
135 println!(" Object4: '{}'", unsafe { obj4.as_ref() });
136
137 // Trigger garbage collection for partition1 again to collect unreferenced objects
138 println!("\nTrigger garbage collection for partition1 again...");
139 // obj2 is no longer explicitly un-rooted, but we can simulate it going out of scope
140 // to test collection. For this example, we'll just collect other garbage.
141 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
142 println!(" Collected {} bytes", freed);
143
144 // Verify remaining root objects are still valid
145 println!("\nVerify remaining root objects are still valid:");
146 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
147 println!(" Object2: {} (still a root)", unsafe { obj2.as_ref() });
148
149 // Demonstrate automatic garbage collection
150 println!("\nDemonstrate automatic garbage collection...");
151
152 // Create a small partition to demonstrate automatic GC
153 let small_partition = heap.create_partition(64 * 1024, 16 * 1024);
154
155 // Allocate multiple objects to fill partition
156 for i in 0..5 {
157 let _obj = unsafe { heap.alloc_raw(small_partition, MyString(format!("Object {}", i))) }
158 .map_err(|(err, _)| err)?;
159 }
160
161 println!(" Allocated 5 objects in small partition");
162
163 // Demonstrate weak references
164 println!("\nDemonstrate weak references:");
165 let weak_ref = heap.downgrade(&obj1);
166 println!(" Created weak reference: {:?}", weak_ref);
167
168 // Upgrade weak reference
169 match weak_ref.upgrade(&heap) {
170 Some(strong_ref) => {
171 println!(" Weak reference upgrade successful: '{}'", &*strong_ref);
172 }
173 None => {
174 println!(" Weak reference upgrade failed");
175 }
176 }
177
178 // Demonstrate complex types with GC references
179 println!("\nDemonstrate complex types with GC references:");
180 let mut node1 =
181 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 1")) }.map_err(|(err, _)| err)?;
182 let mut node2 =
183 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 2")) }.map_err(|(err, _)| err)?;
184
185 // Establish references between nodes
186 {
187 unsafe {
188 node1.with_write_barrier(&mut heap, |n| n.add_child(node2));
189 }
190 unsafe {
191 node2.with_write_barrier(&mut heap, |n| n.add_child(node1));
192 }
193 }
194
195 println!(" Created node1: {}", unsafe { node1.as_ref() });
196 println!(" Created node2: {}", unsafe { node2.as_ref() });
197
198 // Trigger garbage collection, verify circular references are handled correctly
199 println!("\nGarbage collection for handling circular references...");
200 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
201 println!(" 回收了 {} 字节内存", freed);
202
203 // Demonstrate partition deletion
204 println!("\nDemonstrate partition deletion:");
205
206 // Create an empty partition
207 let empty_partition = heap.create_partition(64 * 1024, 16 * 1024);
208 println!(" Created empty partition: {:?}", empty_partition);
209
210 // Delete empty partition
211 heap.remove_partition(empty_partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
212 println!(" Deleted empty partition successfully");
213
214 // Delete non-empty partition
215 heap.remove_partition(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
216 println!(" Deleted non-empty partition successfully");
217
218 println!("\nExample completed!");
219 Ok(())
220}pub const fn opaque(&self) -> *mut u8
pub const fn set_opaque(&mut self, opaque: *mut u8)
Sourcepub fn memory_limit(&self) -> usize
pub fn memory_limit(&self) -> usize
Examples found in repository?
156fn benchmark_memory_efficiency() {
157 println!("\nTesting memory usage efficiency...");
158
159 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
160 context.set_memory_limit(1024 * 1024); // 1MB global limit
161 let partition = context.create_partition(64 * 1024, 16 * 1024);
162
163 // Allocate many small objects
164 let small_objects_count = 1000;
165 let mut small_objects = Vec::new();
166
167 for _i in 0..small_objects_count {
168 let obj = unsafe { context.alloc_raw(partition, SmallData {}) }.unwrap();
169 small_objects.push(obj);
170 }
171
172 if let Some(partition_info) = context.partition(partition) {
173 let used = partition_info.memory_used();
174 let limit = context.memory_limit();
175 let efficiency = if limit > 0 {
176 (used as f64 / limit as f64) * 100.0
177 } else {
178 0.0
179 };
180
181 println!(" After allocating {} small objects:", small_objects_count);
182 println!(
183 " Memory usage: {}/{} bytes ({:.1}%)",
184 used, limit, efficiency
185 );
186 println!(
187 " Average overhead per object: {} bytes",
188 if small_objects_count > 0 {
189 used / small_objects_count
190 } else {
191 0
192 }
193 );
194 }
195
196 // Collect all objects
197 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
198 println!(" Collected all objects, freed {} bytes", freed);
199
200 // Verify complete memory collection
201 if let Some(partition_info) = context.partition(partition) {
202 let used_after = partition_info.memory_used();
203 println!(" Memory usage after collection: {} bytes", used_after);
204 println!(
205 " Memory collection rate: {:.1}%",
206 if freed > 0 {
207 (freed as f64 / (freed + used_after) as f64) * 100.0
208 } else {
209 0.0
210 }
211 );
212 }
213}More examples
47fn main() -> GcResult<()> {
48 println!("=== Basic usage example of partitioned garbage collection system ===");
49
50 // Create garbage collection context
51 let mut heap = GcHeap::new(&GC_TYPE_REGISTRY);
52
53 println!("Initial state:");
54 println!(" Number of partitions: {}", heap.partition_ids().len());
55
56 // Create two partitions
57 println!("\nCreate partitions:");
58 let partition1 = heap.create_partition(64 * 1024, 16 * 1024);
59 let partition2 = heap.create_partition(64 * 1024, 16 * 1024);
60 println!(" Created partition1: {:?}", partition1);
61 println!(" Created partition2: {:?}", partition2);
62 println!(" Number of partitions: {}", heap.partition_ids().len());
63
64 // Allocate objects in partition1
65 println!("\nAllocate objects in partition1:");
66 let obj1 = unsafe { heap.alloc_raw(partition1, MyString(String::from("Hello"))) }
67 .map_err(|(err, _)| err)?;
68 let obj2 = unsafe { heap.alloc_raw(partition1, MyI32(42)) }.map_err(|(err, _)| err)?;
69 let obj3 = unsafe { heap.alloc_raw(partition1, MyString(String::from("VectorData"))) }
70 .map_err(|(err, _)| err)?;
71
72 println!(" Created string: '{}'", unsafe { obj1.as_ref() });
73 println!(" Created number: {}", unsafe { obj2.as_ref() });
74 println!(" Created string: '{}'", unsafe { obj3.as_ref() });
75
76 // Allocate objects in partition2
77 println!("\nAllocate objects in partition2:");
78 let obj4 = unsafe { heap.alloc_raw(partition2, MyString(String::from("World"))) }
79 .map_err(|(err, _)| err)?;
80 let obj5 = unsafe { heap.alloc_raw(partition2, MyI32(99)) }.map_err(|(err, _)| err)?;
81
82 println!(" Created string: '{}'", unsafe { obj4.as_ref() });
83 println!(" Created number: {}", unsafe { obj5.as_ref() });
84
85 // Display partition status
86 println!("\nPartition status:");
87 for partition_id in heap.partition_ids() {
88 if let Some(partition) = heap.partition(partition_id) {
89 let limit = heap.memory_limit();
90 let usage = if limit > 0 {
91 format!(
92 "{}/{} bytes ({:.1}%)",
93 partition.memory_used(),
94 limit,
95 (partition.memory_used() as f64 / limit as f64) * 100.0
96 )
97 } else {
98 format!("{}/∞ bytes", partition.memory_used())
99 };
100 println!(
101 " {:?}: {} [自动GC: {}]",
102 partition_id,
103 usage,
104 if heap.gc_threshold() > 0 {
105 "Enabled"
106 } else {
107 "Disabled"
108 }
109 );
110 }
111 }
112
113 // Root objects are now implicitly managed by stack variables (e.g., obj1, obj2).
114 // No explicit `set_root` calls are needed for them.
115 println!("\nRoot objects are held by variables:");
116 println!(" Roots: obj1, obj2, obj3, obj4, obj5");
117
118 // Manually trigger garbage collection for partition1
119 println!("\nManually trigger garbage collection for partition1...");
120 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
121 println!(" Collected {} bytes", freed);
122
123 // Verify root objects are still valid
124 println!("\nVerify partition1 root objects are still valid:");
125 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
126 println!(" Object2: {}", unsafe { obj2.as_ref() });
127
128 // Manually trigger garbage collection for partition2
129 println!("\nManually trigger garbage collection for partition2...");
130 let freed = heap.garbage_collect(partition2, GcHeap::DUMMY_DISPOSE_CALLBACK);
131 println!(" Collected {} bytes", freed);
132
133 // Verify partition2 root objects are still valid
134 println!("\nVerify partition2 root objects are still valid:");
135 println!(" Object4: '{}'", unsafe { obj4.as_ref() });
136
137 // Trigger garbage collection for partition1 again to collect unreferenced objects
138 println!("\nTrigger garbage collection for partition1 again...");
139 // obj2 is no longer explicitly un-rooted, but we can simulate it going out of scope
140 // to test collection. For this example, we'll just collect other garbage.
141 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
142 println!(" Collected {} bytes", freed);
143
144 // Verify remaining root objects are still valid
145 println!("\nVerify remaining root objects are still valid:");
146 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
147 println!(" Object2: {} (still a root)", unsafe { obj2.as_ref() });
148
149 // Demonstrate automatic garbage collection
150 println!("\nDemonstrate automatic garbage collection...");
151
152 // Create a small partition to demonstrate automatic GC
153 let small_partition = heap.create_partition(64 * 1024, 16 * 1024);
154
155 // Allocate multiple objects to fill partition
156 for i in 0..5 {
157 let _obj = unsafe { heap.alloc_raw(small_partition, MyString(format!("Object {}", i))) }
158 .map_err(|(err, _)| err)?;
159 }
160
161 println!(" Allocated 5 objects in small partition");
162
163 // Demonstrate weak references
164 println!("\nDemonstrate weak references:");
165 let weak_ref = heap.downgrade(&obj1);
166 println!(" Created weak reference: {:?}", weak_ref);
167
168 // Upgrade weak reference
169 match weak_ref.upgrade(&heap) {
170 Some(strong_ref) => {
171 println!(" Weak reference upgrade successful: '{}'", &*strong_ref);
172 }
173 None => {
174 println!(" Weak reference upgrade failed");
175 }
176 }
177
178 // Demonstrate complex types with GC references
179 println!("\nDemonstrate complex types with GC references:");
180 let mut node1 =
181 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 1")) }.map_err(|(err, _)| err)?;
182 let mut node2 =
183 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 2")) }.map_err(|(err, _)| err)?;
184
185 // Establish references between nodes
186 {
187 unsafe {
188 node1.with_write_barrier(&mut heap, |n| n.add_child(node2));
189 }
190 unsafe {
191 node2.with_write_barrier(&mut heap, |n| n.add_child(node1));
192 }
193 }
194
195 println!(" Created node1: {}", unsafe { node1.as_ref() });
196 println!(" Created node2: {}", unsafe { node2.as_ref() });
197
198 // Trigger garbage collection, verify circular references are handled correctly
199 println!("\nGarbage collection for handling circular references...");
200 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
201 println!(" 回收了 {} 字节内存", freed);
202
203 // Demonstrate partition deletion
204 println!("\nDemonstrate partition deletion:");
205
206 // Create an empty partition
207 let empty_partition = heap.create_partition(64 * 1024, 16 * 1024);
208 println!(" Created empty partition: {:?}", empty_partition);
209
210 // Delete empty partition
211 heap.remove_partition(empty_partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
212 println!(" Deleted empty partition successfully");
213
214 // Delete non-empty partition
215 heap.remove_partition(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
216 println!(" Deleted non-empty partition successfully");
217
218 println!("\nExample completed!");
219 Ok(())
220}Sourcepub fn set_memory_limit(&mut self, limit: usize) -> usize
pub fn set_memory_limit(&mut self, limit: usize) -> usize
Examples found in repository?
34fn demonstrate_out_of_memory() -> GcResult<()> {
35 println!("1. Create limited memory partition...");
36
37 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
38 context.set_memory_limit(2048); // 2KB global limit
39 let partition_id = context.create_partition(64 * 1024, 16 * 1024);
40
41 // Allocate first large object (1KB + header)
42 println!("2. Allocate first large object...");
43 let gc1: GcRef<LargeData> =
44 match unsafe { context.alloc_raw(partition_id, LargeData { data: [0; 1024] }) } {
45 Ok(gc_ref) => {
46 println!(" ✓ Successfully allocated first object (1KB)");
47 gc_ref
48 }
49 Err((error, _)) => {
50 println!(" ✗ First object allocation failed: {:?}", error);
51 return Ok(());
52 }
53 };
54
55 // Allocate second large object (1KB + header) - should exceed 2KB limit
56 println!("3. Try to allocate second large object...");
57 match unsafe { context.alloc_raw(partition_id, LargeData { data: [0; 1024] }) } {
58 Err((GcError::PartitionFull, _)) => {
59 println!(" ✓ Correctly detected partition full error");
60 }
61 Ok(_) => {
62 println!(" ✗ Expected partition full error, but allocation succeeded");
63 return Ok(());
64 }
65 Err((other_error, _)) => {
66 println!(
67 " ✗ Expected partition full error, but got: {:?}",
68 other_error
69 );
70 return Ok(());
71 }
72 }
73
74 // Clean up - through garbage collection instead of manual release
75 println!(" ✓ Automatic cleanup through GC");
76 context.garbage_collect(partition_id, GcHeap::DUMMY_DISPOSE_CALLBACK);
77
78 Ok(())
79}
80
81/// Demonstrate partition management errors
82fn demonstrate_partition_management_errors() -> GcResult<()> {
83 println!("1. Test non-existent partition operations...");
84
85 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
86 let invalid_partition = gc_lite::GcPartitionId(9999); // Non-existent partition
87
88 // Test allocating objects in non-existent partition
89 match unsafe {
90 context.alloc_raw(
91 invalid_partition,
92 TestData {
93 value: 42,
94 name: "test".to_string(),
95 },
96 )
97 } {
98 Err((GcError::PartitionNotFound, _)) => {
99 println!(" ✓ Allocating objects in non-existent partition returns correct error");
100 }
101 Ok(_) => {
102 println!(" ✗ Expected partition not found error, but allocation succeeded");
103 }
104 Err((other_error, _)) => {
105 println!(
106 " ✗ Expected partition not found error, but got: {:?}",
107 other_error
108 );
109 }
110 }
111
112 // Test getting non-existent partition information
113 let partition_info = context.partition(invalid_partition);
114 assert!(
115 partition_info.is_none(),
116 "Non-existent partition should return None"
117 );
118 println!(" ✓ Getting non-existent partition info returns None");
119
120 // Test removing non-existent partition (remove_partition doesn't return error, just silently fails)
121 context.remove_partition(invalid_partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
122 println!(" ✓ Removing non-existent partition silently fails");
123
124 println!("\n2. Test non-empty partition deletion...");
125 let partition_id = context.create_partition(64 * 1024, 16 * 1024);
126
127 // Allocate objects in partition
128 let obj = unsafe {
129 context.alloc_raw(
130 partition_id,
131 TestData {
132 value: 1,
133 name: "obj".to_string(),
134 },
135 )
136 }
137 .unwrap();
138 let _ = obj;
139
140 // Try to delete non-empty partition (remove_partition will force cleanup)
141 context.remove_partition(partition_id, GcHeap::DUMMY_DISPOSE_CALLBACK);
142 println!(" ✓ Successfully deleted non-empty partition (root objects were force cleaned)");
143
144 Ok(())
145}
146
147/// Demonstrate GC threshold API errors
148fn demonstrate_gc_threshold_errors() -> GcResult<()> {
149 println!("1. Test GC threshold API...");
150
151 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
152 context.set_memory_limit(1024);
153 let _partition_id = context.create_partition(64 * 1024, 16 * 1024);
154
155 // Test default values
156 println!("2. Test default threshold...");
157 assert_eq!(context.gc_threshold(), 0);
158 println!(" ✓ Default threshold is 0, automatic GC disabled");
159
160 // Test setting threshold
161 println!("3. Test setting threshold...");
162 context.set_gc_threshold(512);
163 assert_eq!(context.gc_threshold(), 512);
164 println!(" ✓ Successfully set threshold to 512, automatic GC enabled");
165
166 // Test setting threshold exceeding memory limit
167 println!("4. Test setting threshold exceeding memory limit...");
168 context.set_gc_threshold(2048);
169 // Since threshold exceeds memory limit, will be capped at 0.8x of limit (1024 * 8 / 10 = 819)
170 assert_eq!(context.gc_threshold(), 819);
171 println!(
172 " ✓ Setting threshold exceeding memory limit automatically adjusted to 0.8x of memory limit"
173 );
174
175 // Test disabling automatic GC
176 println!("5. Test disabling automatic GC...");
177 context.set_gc_threshold(0);
178 assert_eq!(context.gc_threshold(), 0);
179 println!(" ✓ Successfully disabled automatic GC, threshold set to 0");
180
181 Ok(())
182}More examples
156fn benchmark_memory_efficiency() {
157 println!("\nTesting memory usage efficiency...");
158
159 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
160 context.set_memory_limit(1024 * 1024); // 1MB global limit
161 let partition = context.create_partition(64 * 1024, 16 * 1024);
162
163 // Allocate many small objects
164 let small_objects_count = 1000;
165 let mut small_objects = Vec::new();
166
167 for _i in 0..small_objects_count {
168 let obj = unsafe { context.alloc_raw(partition, SmallData {}) }.unwrap();
169 small_objects.push(obj);
170 }
171
172 if let Some(partition_info) = context.partition(partition) {
173 let used = partition_info.memory_used();
174 let limit = context.memory_limit();
175 let efficiency = if limit > 0 {
176 (used as f64 / limit as f64) * 100.0
177 } else {
178 0.0
179 };
180
181 println!(" After allocating {} small objects:", small_objects_count);
182 println!(
183 " Memory usage: {}/{} bytes ({:.1}%)",
184 used, limit, efficiency
185 );
186 println!(
187 " Average overhead per object: {} bytes",
188 if small_objects_count > 0 {
189 used / small_objects_count
190 } else {
191 0
192 }
193 );
194 }
195
196 // Collect all objects
197 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
198 println!(" Collected all objects, freed {} bytes", freed);
199
200 // Verify complete memory collection
201 if let Some(partition_info) = context.partition(partition) {
202 let used_after = partition_info.memory_used();
203 println!(" Memory usage after collection: {} bytes", used_after);
204 println!(
205 " Memory collection rate: {:.1}%",
206 if freed > 0 {
207 (freed as f64 / (freed + used_after) as f64) * 100.0
208 } else {
209 0.0
210 }
211 );
212 }
213}
214
215/// Test automatic GC threshold performance
216fn benchmark_auto_gc_threshold() {
217 println!("\nTesting automatic GC threshold performance...");
218
219 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
220 context.set_memory_limit(2048); // 2KB global limit
221 let partition = context.create_partition(64 * 1024, 16 * 1024);
222
223 // Set automatic GC threshold to 1.5KB
224 context.set_gc_threshold(1500);
225
226 // Allocate objects until automatic GC is triggered
227 let mut allocated_bytes = 0;
228 let mut object_count = 0;
229
230 println!(" Allocating objects until automatic GC is triggered...");
231
232 for _i in 0..100 {
233 // Try at most 100 times
234 // Allocate objects of about 100 bytes
235 let node = SimpleNode {
236 _data: vec![0u8; 100],
237 };
238 match unsafe { context.alloc_raw(partition, node) } {
239 Ok(_gc_ref) => {
240 allocated_bytes += 100 + std::mem::size_of::<GcRef<SimpleNode>>(); // Estimated size
241 object_count += 1;
242
243 // Check if approaching threshold
244 if let Some(partition_info) = context.partition(partition)
245 && partition_info.memory_used() >= 1500
246 {
247 println!(
248 " Reached automatic GC threshold, allocated {} objects",
249 object_count
250 );
251 println!(" Estimated allocated memory: {} bytes", allocated_bytes);
252 println!(
253 " Actual memory usage: {} bytes",
254 partition_info.memory_used()
255 );
256 break;
257 }
258 }
259 Err(_) => {
260 println!(" Allocation failed, automatic GC may have been triggered");
261 break;
262 }
263 }
264 }
265
266 // Manually trigger GC to see effect
267 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
268 println!(" Manual GC freed {} bytes", freed);
269}Sourcepub fn gc_threshold(&self) -> usize
pub fn gc_threshold(&self) -> usize
Examples found in repository?
148fn demonstrate_gc_threshold_errors() -> GcResult<()> {
149 println!("1. Test GC threshold API...");
150
151 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
152 context.set_memory_limit(1024);
153 let _partition_id = context.create_partition(64 * 1024, 16 * 1024);
154
155 // Test default values
156 println!("2. Test default threshold...");
157 assert_eq!(context.gc_threshold(), 0);
158 println!(" ✓ Default threshold is 0, automatic GC disabled");
159
160 // Test setting threshold
161 println!("3. Test setting threshold...");
162 context.set_gc_threshold(512);
163 assert_eq!(context.gc_threshold(), 512);
164 println!(" ✓ Successfully set threshold to 512, automatic GC enabled");
165
166 // Test setting threshold exceeding memory limit
167 println!("4. Test setting threshold exceeding memory limit...");
168 context.set_gc_threshold(2048);
169 // Since threshold exceeds memory limit, will be capped at 0.8x of limit (1024 * 8 / 10 = 819)
170 assert_eq!(context.gc_threshold(), 819);
171 println!(
172 " ✓ Setting threshold exceeding memory limit automatically adjusted to 0.8x of memory limit"
173 );
174
175 // Test disabling automatic GC
176 println!("5. Test disabling automatic GC...");
177 context.set_gc_threshold(0);
178 assert_eq!(context.gc_threshold(), 0);
179 println!(" ✓ Successfully disabled automatic GC, threshold set to 0");
180
181 Ok(())
182}More examples
47fn main() -> GcResult<()> {
48 println!("=== Basic usage example of partitioned garbage collection system ===");
49
50 // Create garbage collection context
51 let mut heap = GcHeap::new(&GC_TYPE_REGISTRY);
52
53 println!("Initial state:");
54 println!(" Number of partitions: {}", heap.partition_ids().len());
55
56 // Create two partitions
57 println!("\nCreate partitions:");
58 let partition1 = heap.create_partition(64 * 1024, 16 * 1024);
59 let partition2 = heap.create_partition(64 * 1024, 16 * 1024);
60 println!(" Created partition1: {:?}", partition1);
61 println!(" Created partition2: {:?}", partition2);
62 println!(" Number of partitions: {}", heap.partition_ids().len());
63
64 // Allocate objects in partition1
65 println!("\nAllocate objects in partition1:");
66 let obj1 = unsafe { heap.alloc_raw(partition1, MyString(String::from("Hello"))) }
67 .map_err(|(err, _)| err)?;
68 let obj2 = unsafe { heap.alloc_raw(partition1, MyI32(42)) }.map_err(|(err, _)| err)?;
69 let obj3 = unsafe { heap.alloc_raw(partition1, MyString(String::from("VectorData"))) }
70 .map_err(|(err, _)| err)?;
71
72 println!(" Created string: '{}'", unsafe { obj1.as_ref() });
73 println!(" Created number: {}", unsafe { obj2.as_ref() });
74 println!(" Created string: '{}'", unsafe { obj3.as_ref() });
75
76 // Allocate objects in partition2
77 println!("\nAllocate objects in partition2:");
78 let obj4 = unsafe { heap.alloc_raw(partition2, MyString(String::from("World"))) }
79 .map_err(|(err, _)| err)?;
80 let obj5 = unsafe { heap.alloc_raw(partition2, MyI32(99)) }.map_err(|(err, _)| err)?;
81
82 println!(" Created string: '{}'", unsafe { obj4.as_ref() });
83 println!(" Created number: {}", unsafe { obj5.as_ref() });
84
85 // Display partition status
86 println!("\nPartition status:");
87 for partition_id in heap.partition_ids() {
88 if let Some(partition) = heap.partition(partition_id) {
89 let limit = heap.memory_limit();
90 let usage = if limit > 0 {
91 format!(
92 "{}/{} bytes ({:.1}%)",
93 partition.memory_used(),
94 limit,
95 (partition.memory_used() as f64 / limit as f64) * 100.0
96 )
97 } else {
98 format!("{}/∞ bytes", partition.memory_used())
99 };
100 println!(
101 " {:?}: {} [自动GC: {}]",
102 partition_id,
103 usage,
104 if heap.gc_threshold() > 0 {
105 "Enabled"
106 } else {
107 "Disabled"
108 }
109 );
110 }
111 }
112
113 // Root objects are now implicitly managed by stack variables (e.g., obj1, obj2).
114 // No explicit `set_root` calls are needed for them.
115 println!("\nRoot objects are held by variables:");
116 println!(" Roots: obj1, obj2, obj3, obj4, obj5");
117
118 // Manually trigger garbage collection for partition1
119 println!("\nManually trigger garbage collection for partition1...");
120 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
121 println!(" Collected {} bytes", freed);
122
123 // Verify root objects are still valid
124 println!("\nVerify partition1 root objects are still valid:");
125 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
126 println!(" Object2: {}", unsafe { obj2.as_ref() });
127
128 // Manually trigger garbage collection for partition2
129 println!("\nManually trigger garbage collection for partition2...");
130 let freed = heap.garbage_collect(partition2, GcHeap::DUMMY_DISPOSE_CALLBACK);
131 println!(" Collected {} bytes", freed);
132
133 // Verify partition2 root objects are still valid
134 println!("\nVerify partition2 root objects are still valid:");
135 println!(" Object4: '{}'", unsafe { obj4.as_ref() });
136
137 // Trigger garbage collection for partition1 again to collect unreferenced objects
138 println!("\nTrigger garbage collection for partition1 again...");
139 // obj2 is no longer explicitly un-rooted, but we can simulate it going out of scope
140 // to test collection. For this example, we'll just collect other garbage.
141 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
142 println!(" Collected {} bytes", freed);
143
144 // Verify remaining root objects are still valid
145 println!("\nVerify remaining root objects are still valid:");
146 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
147 println!(" Object2: {} (still a root)", unsafe { obj2.as_ref() });
148
149 // Demonstrate automatic garbage collection
150 println!("\nDemonstrate automatic garbage collection...");
151
152 // Create a small partition to demonstrate automatic GC
153 let small_partition = heap.create_partition(64 * 1024, 16 * 1024);
154
155 // Allocate multiple objects to fill partition
156 for i in 0..5 {
157 let _obj = unsafe { heap.alloc_raw(small_partition, MyString(format!("Object {}", i))) }
158 .map_err(|(err, _)| err)?;
159 }
160
161 println!(" Allocated 5 objects in small partition");
162
163 // Demonstrate weak references
164 println!("\nDemonstrate weak references:");
165 let weak_ref = heap.downgrade(&obj1);
166 println!(" Created weak reference: {:?}", weak_ref);
167
168 // Upgrade weak reference
169 match weak_ref.upgrade(&heap) {
170 Some(strong_ref) => {
171 println!(" Weak reference upgrade successful: '{}'", &*strong_ref);
172 }
173 None => {
174 println!(" Weak reference upgrade failed");
175 }
176 }
177
178 // Demonstrate complex types with GC references
179 println!("\nDemonstrate complex types with GC references:");
180 let mut node1 =
181 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 1")) }.map_err(|(err, _)| err)?;
182 let mut node2 =
183 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 2")) }.map_err(|(err, _)| err)?;
184
185 // Establish references between nodes
186 {
187 unsafe {
188 node1.with_write_barrier(&mut heap, |n| n.add_child(node2));
189 }
190 unsafe {
191 node2.with_write_barrier(&mut heap, |n| n.add_child(node1));
192 }
193 }
194
195 println!(" Created node1: {}", unsafe { node1.as_ref() });
196 println!(" Created node2: {}", unsafe { node2.as_ref() });
197
198 // Trigger garbage collection, verify circular references are handled correctly
199 println!("\nGarbage collection for handling circular references...");
200 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
201 println!(" 回收了 {} 字节内存", freed);
202
203 // Demonstrate partition deletion
204 println!("\nDemonstrate partition deletion:");
205
206 // Create an empty partition
207 let empty_partition = heap.create_partition(64 * 1024, 16 * 1024);
208 println!(" Created empty partition: {:?}", empty_partition);
209
210 // Delete empty partition
211 heap.remove_partition(empty_partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
212 println!(" Deleted empty partition successfully");
213
214 // Delete non-empty partition
215 heap.remove_partition(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
216 println!(" Deleted non-empty partition successfully");
217
218 println!("\nExample completed!");
219 Ok(())
220}Sourcepub fn set_gc_threshold(&mut self, threshold: usize) -> usize
pub fn set_gc_threshold(&mut self, threshold: usize) -> usize
Examples found in repository?
148fn demonstrate_gc_threshold_errors() -> GcResult<()> {
149 println!("1. Test GC threshold API...");
150
151 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
152 context.set_memory_limit(1024);
153 let _partition_id = context.create_partition(64 * 1024, 16 * 1024);
154
155 // Test default values
156 println!("2. Test default threshold...");
157 assert_eq!(context.gc_threshold(), 0);
158 println!(" ✓ Default threshold is 0, automatic GC disabled");
159
160 // Test setting threshold
161 println!("3. Test setting threshold...");
162 context.set_gc_threshold(512);
163 assert_eq!(context.gc_threshold(), 512);
164 println!(" ✓ Successfully set threshold to 512, automatic GC enabled");
165
166 // Test setting threshold exceeding memory limit
167 println!("4. Test setting threshold exceeding memory limit...");
168 context.set_gc_threshold(2048);
169 // Since threshold exceeds memory limit, will be capped at 0.8x of limit (1024 * 8 / 10 = 819)
170 assert_eq!(context.gc_threshold(), 819);
171 println!(
172 " ✓ Setting threshold exceeding memory limit automatically adjusted to 0.8x of memory limit"
173 );
174
175 // Test disabling automatic GC
176 println!("5. Test disabling automatic GC...");
177 context.set_gc_threshold(0);
178 assert_eq!(context.gc_threshold(), 0);
179 println!(" ✓ Successfully disabled automatic GC, threshold set to 0");
180
181 Ok(())
182}More examples
216fn benchmark_auto_gc_threshold() {
217 println!("\nTesting automatic GC threshold performance...");
218
219 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
220 context.set_memory_limit(2048); // 2KB global limit
221 let partition = context.create_partition(64 * 1024, 16 * 1024);
222
223 // Set automatic GC threshold to 1.5KB
224 context.set_gc_threshold(1500);
225
226 // Allocate objects until automatic GC is triggered
227 let mut allocated_bytes = 0;
228 let mut object_count = 0;
229
230 println!(" Allocating objects until automatic GC is triggered...");
231
232 for _i in 0..100 {
233 // Try at most 100 times
234 // Allocate objects of about 100 bytes
235 let node = SimpleNode {
236 _data: vec![0u8; 100],
237 };
238 match unsafe { context.alloc_raw(partition, node) } {
239 Ok(_gc_ref) => {
240 allocated_bytes += 100 + std::mem::size_of::<GcRef<SimpleNode>>(); // Estimated size
241 object_count += 1;
242
243 // Check if approaching threshold
244 if let Some(partition_info) = context.partition(partition)
245 && partition_info.memory_used() >= 1500
246 {
247 println!(
248 " Reached automatic GC threshold, allocated {} objects",
249 object_count
250 );
251 println!(" Estimated allocated memory: {} bytes", allocated_bytes);
252 println!(
253 " Actual memory usage: {} bytes",
254 partition_info.memory_used()
255 );
256 break;
257 }
258 }
259 Err(_) => {
260 println!(" Allocation failed, automatic GC may have been triggered");
261 break;
262 }
263 }
264 }
265
266 // Manually trigger GC to see effect
267 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
268 println!(" Manual GC freed {} bytes", freed);
269}pub fn set_root_node(&mut self, node: NonNull<GcHead>)
Sourcepub fn contains(&self, node: NonNull<GcHead>) -> bool
pub fn contains(&self, node: NonNull<GcHead>) -> bool
Check if node was allocated in this heap
Examples found in repository?
292fn demonstrate_cross_context_detection() -> GcResult<()> {
293 println!("1. Create two independent heaps...");
294
295 let mut heap1 = new_heap();
296 let mut heap2 = new_heap();
297
298 let partition1 = heap1.create_partition(64 * 1024, 16 * 1024);
299 let partition2 = heap2.create_partition(64 * 1024, 16 * 1024);
300
301 let obj1 = unsafe {
302 heap1.alloc_root_raw(
303 partition1,
304 TestData {
305 value: 1,
306 name: "obj1".to_string(),
307 },
308 )
309 }
310 .map_err(|(e, _)| e)?;
311 let obj2 = unsafe {
312 heap2.alloc_raw(
313 partition2,
314 TestData {
315 value: 2,
316 name: "obj2".to_string(),
317 },
318 )
319 }
320 .map_err(|(e, _)| e)?;
321
322 println!("2. Test object source detection...");
323 assert!(heap1.contains(obj1.node_ptr()), "obj1 should be from heap1");
324 assert!(
325 !heap1.contains(obj2.node_ptr()),
326 "obj2 should not be from heap1"
327 );
328 assert!(heap2.contains(obj2.node_ptr()), "obj2 should be from heap2");
329 assert!(
330 !heap2.contains(obj1.node_ptr()),
331 "obj1 should not be from heap2"
332 );
333
334 println!(" ✓ Cross-context detection correct");
335
336 // Clean up
337 heap1.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
338 heap2.garbage_collect(partition2, GcHeap::DUMMY_DISPOSE_CALLBACK);
339
340 Ok(())
341}Sourcepub fn protect_node(
&mut self,
scope_stack_id: GcScopeStackId,
node: NonNull<GcHead>,
) -> bool
pub fn protect_node( &mut self, scope_stack_id: GcScopeStackId, node: NonNull<GcHead>, ) -> bool
Protect node from being gc collected.
- if node is local or root, it’s protected, returns true
- otherwise if has current scope, add node to current scope and returns true
- can’t protect, returns false
Sourcepub fn protect_nodes_iter(
&mut self,
scope_stack_id: GcScopeStackId,
nodes: impl Iterator<Item = NonNull<GcHead>>,
)
pub fn protect_nodes_iter( &mut self, scope_stack_id: GcScopeStackId, nodes: impl Iterator<Item = NonNull<GcHead>>, )
Protect nodes from being gc collected, for each node do following steps:
- if node is local or root, do nothing
- if has current scope, add node to current scope
- can’t protect, returns false
Sourcepub fn protect_nodes(
&mut self,
scope_stack_id: GcScopeStackId,
nodes: &[NonNull<GcHead>],
)
pub fn protect_nodes( &mut self, scope_stack_id: GcScopeStackId, nodes: &[NonNull<GcHead>], )
Protect nodes from being gc collected, for each node do following steps:
- if node is local or root, do nothing
- if has current scope, add node to current scope
- can’t protect, returns false
pub const fn memory_used(&self) -> usize
Source§impl GcHeap
impl GcHeap
pub fn add_gray_node(&mut self, node: NonNull<GcHead>)
pub fn mark_reset(&mut self, partition_id: GcPartitionId)
pub fn mark_prepare(&mut self, partition_id: GcPartitionId)
pub fn mark_grays( &mut self, partition_id: GcPartitionId, max_steps: usize, ) -> bool
pub fn mark(&mut self, partition_id: GcPartitionId, max_steps: usize) -> bool
Sourcepub fn sweep(
&mut self,
partition_id: GcPartitionId,
on_dispose: impl Fn(&GcHeap, &GcHead),
) -> usize
pub fn sweep( &mut self, partition_id: GcPartitionId, on_dispose: impl Fn(&GcHeap, &GcHead), ) -> usize
dispose white nodes in the partition.
on_dispose is called BEFORE a node will be disposed.
Sourcepub fn garbage_collect(
&mut self,
partition_id: GcPartitionId,
on_dispose: impl Fn(&GcHeap, &GcHead),
) -> usize
pub fn garbage_collect( &mut self, partition_id: GcPartitionId, on_dispose: impl Fn(&GcHeap, &GcHead), ) -> usize
Collect garbage on given partition, call notify with node BEFORE it is disposed.
Examples found in repository?
76fn demonstrate_weak_references(
77 heap: &mut GcHeap,
78 partition: gc_lite::GcPartitionId,
79) -> GcResult<()> {
80 println!("1. Create strong and weak references...");
81
82 let strong_ref =
83 unsafe { heap.alloc_root_raw(partition, MyString(String::from("Strong Reference Data"))) }
84 .map_err(|(err, _)| err)?;
85
86 let weak_ref = heap.downgrade(&strong_ref);
87 println!(" Created strong reference: {:?}", strong_ref);
88 println!(" Created weak reference: {:?}", weak_ref);
89
90 // Upgrade weak reference
91 println!("\n2. Upgrade weak reference...");
92 match weak_ref.upgrade(heap) {
93 Some(upgraded) => {
94 let data = &*upgraded;
95 println!(" Weak reference upgrade successful: '{}'", data);
96 assert_eq!(data, "Strong Reference Data");
97 }
98 None => println!(" Weak reference upgrade failed"),
99 }
100
101 // Try upgrading after releasing strong reference
102 println!("\n3. Upgrade weak reference after releasing strong reference...");
103 heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
104
105 match weak_ref.upgrade(heap) {
106 Some(_) => {
107 println!(" Weak reference can still be upgraded (object may still be in memory)")
108 }
109 None => println!(" Weak reference upgrade failed (object has been collected)"),
110 }
111
112 Ok(())
113}
114
115/// Demonstrate circular reference handling
116fn demonstrate_cyclic_references(
117 heap: &mut GcHeap,
118 partition: gc_lite::GcPartitionId,
119) -> GcResult<()> {
120 println!("1. Create circular reference nodes...");
121
122 // Create two mutually referencing nodes
123 let mut node1 = unsafe { heap.alloc_root_raw(partition, CyclicNode::new("Node A")) }
124 .map_err(|(err, _)| err)?;
125 let mut node2 = unsafe { heap.alloc_root_raw(partition, CyclicNode::new("Node B")) }
126 .map_err(|(err, _)| err)?;
127
128 // Establish circular references
129 {
130 unsafe {
131 node1.with_write_barrier(heap, |n| n.set_partner(node2));
132 }
133 unsafe {
134 node2.with_write_barrier(heap, |n| n.set_partner(node1));
135 }
136 }
137
138 println!(" Created node1: {}", unsafe { node1.as_ref() });
139 println!(" Created node2: {}", unsafe { node2.as_ref() });
140
141 // Trigger garbage collection
142 println!("\n2. Trigger garbage collection (circular references still exist)...");
143 let freed = heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
144 println!(" 回收了 {} 字节内存", freed);
145
146 // Verify circular references still exist
147 println!("\n3. Verify circular references...");
148 println!(
149 " Node1's partner: {}",
150 unsafe { node1.as_ref() }.get_partner_name()
151 );
152 println!(
153 " Node2's partner: {}",
154 unsafe { node2.as_ref() }.get_partner_name()
155 );
156
157 // Clear root object status, let circular references be collected
158 println!("\n4. Clear root object status and trigger GC again...");
159 let freed = heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
160 println!(
161 " Freed {} bytes of memory (circular references correctly collected)",
162 freed
163 );
164
165 Ok(())
166}
167
168/// Demonstrate complex data structures
169fn demonstrate_complex_structures(
170 heap: &mut GcHeap,
171 partition: gc_lite::GcPartitionId,
172) -> GcResult<()> {
173 println!("1. Create complex data structures...");
174
175 // Create multiple nodes
176 let mut root_node =
177 unsafe { heap.alloc_root_raw(partition, TreeNode::new("Root")) }.map_err(|(err, _)| err)?;
178 let mut child1 =
179 unsafe { heap.alloc_raw(partition, TreeNode::new("Child 1")) }.map_err(|(err, _)| err)?;
180 let child2 =
181 unsafe { heap.alloc_raw(partition, TreeNode::new("Child 2")) }.map_err(|(err, _)| err)?;
182 let grandchild = unsafe { heap.alloc_raw(partition, TreeNode::new("Grandchild")) }
183 .map_err(|(err, _)| err)?;
184
185 // Build tree structure
186 {
187 unsafe {
188 root_node.with_write_barrier(heap, |n| n.add_child(child1));
189 }
190 unsafe {
191 root_node.with_write_barrier(heap, |n| n.add_child(child2));
192 }
193 unsafe {
194 child1.with_write_barrier(heap, |n| n.add_child(grandchild));
195 }
196 }
197
198 // Create data container
199 let container = unsafe {
200 heap.alloc_root_raw(
201 partition,
202 DataContainer {
203 root: root_node,
204 metadata: vec![1, 2, 3],
205 optional_data: Some(child1),
206 },
207 )
208 }
209 .map_err(|(err, _)| err)?;
210
211 println!(" Created tree structure:");
212 println!(" Root -> Child 1 -> Grandchild");
213 println!(" Root -> Child 2");
214 println!(" Created data container");
215
216 // Trigger garbage collection
217 println!("\n2. Trigger garbage collection...");
218 let freed = heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
219 println!(" 回收了 {} 字节内存", freed);
220
221 // Verify data structure integrity
222 println!("\n3. Verify data structure integrity...");
223 {
224 let container_ref = unsafe { container.as_ref() };
225 println!(
226 " Container root node: {}",
227 unsafe { container_ref.root.as_ref() }.name
228 );
229 println!(" Metadata length: {}", container_ref.metadata.len());
230 println!(
231 " Optional data exists: {}",
232 container_ref.optional_data.is_some()
233 );
234 }
235
236 Ok(())
237}
238
239/// Demonstrate reference recovery functionality
240fn demonstrate_reference_recovery(
241 heap: &mut GcHeap,
242 partition: gc_lite::GcPartitionId,
243) -> GcResult<()> {
244 println!("1. Create object and get reference...");
245
246 let original_ref = unsafe {
247 heap.alloc_raw(
248 partition,
249 TestData {
250 value: 42,
251 name: "test".to_string(),
252 },
253 )
254 }
255 .map_err(|(err, _)| err)?;
256
257 let data_ref = unsafe { original_ref.as_ref() };
258 println!(" Original reference: {:?}", original_ref);
259 println!(" Data: {:?}", data_ref);
260
261 // Recover GcRef from reference
262 println!("\n2. Recover GcRef from reference...");
263 let recovered_ref = unsafe { GcRef::try_from_ref(heap, data_ref) };
264
265 match recovered_ref {
266 Some(recovered) => {
267 println!(" Recovery successful: {:?}", recovered);
268 let recovered_data = unsafe { recovered.as_ref() };
269 println!(" Recovered data: {:?}", recovered_data);
270 println!(" Data equal: {}", data_ref == recovered_data);
271 println!(" Reference equal: {}", original_ref == recovered);
272 }
273 None => println!(" Recovery failed (possibly type registration issue)"),
274 }
275
276 // Test invalid reference recovery - create an object not in GC heap
277 println!("\n3. Test invalid reference recovery...");
278 let local_data = TestData {
279 value: 100,
280 name: "local".to_string(),
281 };
282 let invalid_result = unsafe { GcRef::try_from_ref(heap, &local_data) };
283 println!(
284 " Invalid reference recovery result: {:?} (should be None)",
285 invalid_result
286 );
287
288 Ok(())
289}
290
291/// Demonstrate cross-context detection
292fn demonstrate_cross_context_detection() -> GcResult<()> {
293 println!("1. Create two independent heaps...");
294
295 let mut heap1 = new_heap();
296 let mut heap2 = new_heap();
297
298 let partition1 = heap1.create_partition(64 * 1024, 16 * 1024);
299 let partition2 = heap2.create_partition(64 * 1024, 16 * 1024);
300
301 let obj1 = unsafe {
302 heap1.alloc_root_raw(
303 partition1,
304 TestData {
305 value: 1,
306 name: "obj1".to_string(),
307 },
308 )
309 }
310 .map_err(|(e, _)| e)?;
311 let obj2 = unsafe {
312 heap2.alloc_raw(
313 partition2,
314 TestData {
315 value: 2,
316 name: "obj2".to_string(),
317 },
318 )
319 }
320 .map_err(|(e, _)| e)?;
321
322 println!("2. Test object source detection...");
323 assert!(heap1.contains(obj1.node_ptr()), "obj1 should be from heap1");
324 assert!(
325 !heap1.contains(obj2.node_ptr()),
326 "obj2 should not be from heap1"
327 );
328 assert!(heap2.contains(obj2.node_ptr()), "obj2 should be from heap2");
329 assert!(
330 !heap2.contains(obj1.node_ptr()),
331 "obj1 should not be from heap2"
332 );
333
334 println!(" ✓ Cross-context detection correct");
335
336 // Clean up
337 heap1.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
338 heap2.garbage_collect(partition2, GcHeap::DUMMY_DISPOSE_CALLBACK);
339
340 Ok(())
341}More examples
38fn benchmark_object_sizes() {
39 let sizes = [10, 100, 500, 1000, 5000];
40
41 for &size in &sizes {
42 println!("\nTest object count: {}", size);
43
44 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
45 let partition = context.create_partition(64 * 1024, 16 * 1024);
46
47 // Measure allocation performance
48 let alloc_start = Instant::now();
49 let mut objects = Vec::new();
50 for _i in 0..size {
51 let node = unsafe {
52 context.alloc_raw(
53 partition,
54 SimpleNode {
55 _data: vec![0u8; 100],
56 },
57 )
58 } // Each node 100 bytes
59 .unwrap();
60 objects.push(node);
61 }
62 let alloc_duration = alloc_start.elapsed();
63
64 println!(" Allocated {} objects in: {:?}", size, alloc_duration);
65 println!(
66 " Average allocation time per object: {:?}",
67 alloc_duration / size as u32
68 );
69
70 // Measure GC performance (all objects can be collected)
71 let gc_start = Instant::now();
72 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
73 let gc_duration = gc_start.elapsed();
74
75 println!(" GC回收 {} 字节耗时: {:?}", freed, gc_duration);
76 println!(
77 " Average collection time per byte: {:?}",
78 if freed > 0 {
79 gc_duration / freed as u32
80 } else {
81 Duration::from_nanos(0)
82 }
83 );
84 }
85}
86
87/// Test GC performance of complex object graphs
88fn benchmark_complex_graphs() {
89 let sizes = [100, 500, 1000];
90
91 for &size in &sizes {
92 println!("\nTest complex object graph size: {} nodes", size);
93
94 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
95 let partition = context.create_partition(64 * 1024, 16 * 1024);
96
97 // Create complex object graph
98 let graph_start = Instant::now();
99 let mut nodes = Vec::new();
100
101 // Create all nodes
102 for _i in 0..size {
103 let node = unsafe {
104 context.alloc_raw(
105 partition,
106 GraphNode {
107 neighbors: Vec::new(),
108 },
109 )
110 }
111 .unwrap();
112 nodes.push(node);
113 }
114
115 // Establish complex dependencies
116 for i in 0..size {
117 {
118 // Each node points to subsequent nodes
119 for j in 1..=5 {
120 if i + j < size {
121 let n = nodes[i + j];
122 unsafe {
123 nodes[i]
124 .with_write_barrier(&mut context, |node| node.neighbors.push(n));
125 }
126 }
127 }
128 // Every 10 nodes form a cycle
129 if i % 10 == 0 && i + 9 < size {
130 let n = nodes[i];
131 unsafe {
132 nodes[i + 9]
133 .with_write_barrier(&mut context, |node| node.neighbors.push(n));
134 }
135 }
136 }
137 }
138 let graph_duration = graph_start.elapsed();
139
140 println!(" Built complex object graph in: {:?}", graph_duration);
141
142 // Measure GC performance
143 let gc_start = Instant::now();
144 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
145 let gc_duration = gc_start.elapsed();
146
147 println!(" GC回收 {} 字节耗时: {:?}", freed, gc_duration);
148 println!(
149 " Object graph complexity: average {} neighbors per node",
150 if size > 0 { (size * 5) / size } else { 0 }
151 );
152 }
153}
154
155/// Test memory usage efficiency
156fn benchmark_memory_efficiency() {
157 println!("\nTesting memory usage efficiency...");
158
159 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
160 context.set_memory_limit(1024 * 1024); // 1MB global limit
161 let partition = context.create_partition(64 * 1024, 16 * 1024);
162
163 // Allocate many small objects
164 let small_objects_count = 1000;
165 let mut small_objects = Vec::new();
166
167 for _i in 0..small_objects_count {
168 let obj = unsafe { context.alloc_raw(partition, SmallData {}) }.unwrap();
169 small_objects.push(obj);
170 }
171
172 if let Some(partition_info) = context.partition(partition) {
173 let used = partition_info.memory_used();
174 let limit = context.memory_limit();
175 let efficiency = if limit > 0 {
176 (used as f64 / limit as f64) * 100.0
177 } else {
178 0.0
179 };
180
181 println!(" After allocating {} small objects:", small_objects_count);
182 println!(
183 " Memory usage: {}/{} bytes ({:.1}%)",
184 used, limit, efficiency
185 );
186 println!(
187 " Average overhead per object: {} bytes",
188 if small_objects_count > 0 {
189 used / small_objects_count
190 } else {
191 0
192 }
193 );
194 }
195
196 // Collect all objects
197 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
198 println!(" Collected all objects, freed {} bytes", freed);
199
200 // Verify complete memory collection
201 if let Some(partition_info) = context.partition(partition) {
202 let used_after = partition_info.memory_used();
203 println!(" Memory usage after collection: {} bytes", used_after);
204 println!(
205 " Memory collection rate: {:.1}%",
206 if freed > 0 {
207 (freed as f64 / (freed + used_after) as f64) * 100.0
208 } else {
209 0.0
210 }
211 );
212 }
213}
214
215/// Test automatic GC threshold performance
216fn benchmark_auto_gc_threshold() {
217 println!("\nTesting automatic GC threshold performance...");
218
219 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
220 context.set_memory_limit(2048); // 2KB global limit
221 let partition = context.create_partition(64 * 1024, 16 * 1024);
222
223 // Set automatic GC threshold to 1.5KB
224 context.set_gc_threshold(1500);
225
226 // Allocate objects until automatic GC is triggered
227 let mut allocated_bytes = 0;
228 let mut object_count = 0;
229
230 println!(" Allocating objects until automatic GC is triggered...");
231
232 for _i in 0..100 {
233 // Try at most 100 times
234 // Allocate objects of about 100 bytes
235 let node = SimpleNode {
236 _data: vec![0u8; 100],
237 };
238 match unsafe { context.alloc_raw(partition, node) } {
239 Ok(_gc_ref) => {
240 allocated_bytes += 100 + std::mem::size_of::<GcRef<SimpleNode>>(); // Estimated size
241 object_count += 1;
242
243 // Check if approaching threshold
244 if let Some(partition_info) = context.partition(partition)
245 && partition_info.memory_used() >= 1500
246 {
247 println!(
248 " Reached automatic GC threshold, allocated {} objects",
249 object_count
250 );
251 println!(" Estimated allocated memory: {} bytes", allocated_bytes);
252 println!(
253 " Actual memory usage: {} bytes",
254 partition_info.memory_used()
255 );
256 break;
257 }
258 }
259 Err(_) => {
260 println!(" Allocation failed, automatic GC may have been triggered");
261 break;
262 }
263 }
264 }
265
266 // Manually trigger GC to see effect
267 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
268 println!(" Manual GC freed {} bytes", freed);
269}34fn demonstrate_out_of_memory() -> GcResult<()> {
35 println!("1. Create limited memory partition...");
36
37 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
38 context.set_memory_limit(2048); // 2KB global limit
39 let partition_id = context.create_partition(64 * 1024, 16 * 1024);
40
41 // Allocate first large object (1KB + header)
42 println!("2. Allocate first large object...");
43 let gc1: GcRef<LargeData> =
44 match unsafe { context.alloc_raw(partition_id, LargeData { data: [0; 1024] }) } {
45 Ok(gc_ref) => {
46 println!(" ✓ Successfully allocated first object (1KB)");
47 gc_ref
48 }
49 Err((error, _)) => {
50 println!(" ✗ First object allocation failed: {:?}", error);
51 return Ok(());
52 }
53 };
54
55 // Allocate second large object (1KB + header) - should exceed 2KB limit
56 println!("3. Try to allocate second large object...");
57 match unsafe { context.alloc_raw(partition_id, LargeData { data: [0; 1024] }) } {
58 Err((GcError::PartitionFull, _)) => {
59 println!(" ✓ Correctly detected partition full error");
60 }
61 Ok(_) => {
62 println!(" ✗ Expected partition full error, but allocation succeeded");
63 return Ok(());
64 }
65 Err((other_error, _)) => {
66 println!(
67 " ✗ Expected partition full error, but got: {:?}",
68 other_error
69 );
70 return Ok(());
71 }
72 }
73
74 // Clean up - through garbage collection instead of manual release
75 println!(" ✓ Automatic cleanup through GC");
76 context.garbage_collect(partition_id, GcHeap::DUMMY_DISPOSE_CALLBACK);
77
78 Ok(())
79}47fn main() -> GcResult<()> {
48 println!("=== Basic usage example of partitioned garbage collection system ===");
49
50 // Create garbage collection context
51 let mut heap = GcHeap::new(&GC_TYPE_REGISTRY);
52
53 println!("Initial state:");
54 println!(" Number of partitions: {}", heap.partition_ids().len());
55
56 // Create two partitions
57 println!("\nCreate partitions:");
58 let partition1 = heap.create_partition(64 * 1024, 16 * 1024);
59 let partition2 = heap.create_partition(64 * 1024, 16 * 1024);
60 println!(" Created partition1: {:?}", partition1);
61 println!(" Created partition2: {:?}", partition2);
62 println!(" Number of partitions: {}", heap.partition_ids().len());
63
64 // Allocate objects in partition1
65 println!("\nAllocate objects in partition1:");
66 let obj1 = unsafe { heap.alloc_raw(partition1, MyString(String::from("Hello"))) }
67 .map_err(|(err, _)| err)?;
68 let obj2 = unsafe { heap.alloc_raw(partition1, MyI32(42)) }.map_err(|(err, _)| err)?;
69 let obj3 = unsafe { heap.alloc_raw(partition1, MyString(String::from("VectorData"))) }
70 .map_err(|(err, _)| err)?;
71
72 println!(" Created string: '{}'", unsafe { obj1.as_ref() });
73 println!(" Created number: {}", unsafe { obj2.as_ref() });
74 println!(" Created string: '{}'", unsafe { obj3.as_ref() });
75
76 // Allocate objects in partition2
77 println!("\nAllocate objects in partition2:");
78 let obj4 = unsafe { heap.alloc_raw(partition2, MyString(String::from("World"))) }
79 .map_err(|(err, _)| err)?;
80 let obj5 = unsafe { heap.alloc_raw(partition2, MyI32(99)) }.map_err(|(err, _)| err)?;
81
82 println!(" Created string: '{}'", unsafe { obj4.as_ref() });
83 println!(" Created number: {}", unsafe { obj5.as_ref() });
84
85 // Display partition status
86 println!("\nPartition status:");
87 for partition_id in heap.partition_ids() {
88 if let Some(partition) = heap.partition(partition_id) {
89 let limit = heap.memory_limit();
90 let usage = if limit > 0 {
91 format!(
92 "{}/{} bytes ({:.1}%)",
93 partition.memory_used(),
94 limit,
95 (partition.memory_used() as f64 / limit as f64) * 100.0
96 )
97 } else {
98 format!("{}/∞ bytes", partition.memory_used())
99 };
100 println!(
101 " {:?}: {} [自动GC: {}]",
102 partition_id,
103 usage,
104 if heap.gc_threshold() > 0 {
105 "Enabled"
106 } else {
107 "Disabled"
108 }
109 );
110 }
111 }
112
113 // Root objects are now implicitly managed by stack variables (e.g., obj1, obj2).
114 // No explicit `set_root` calls are needed for them.
115 println!("\nRoot objects are held by variables:");
116 println!(" Roots: obj1, obj2, obj3, obj4, obj5");
117
118 // Manually trigger garbage collection for partition1
119 println!("\nManually trigger garbage collection for partition1...");
120 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
121 println!(" Collected {} bytes", freed);
122
123 // Verify root objects are still valid
124 println!("\nVerify partition1 root objects are still valid:");
125 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
126 println!(" Object2: {}", unsafe { obj2.as_ref() });
127
128 // Manually trigger garbage collection for partition2
129 println!("\nManually trigger garbage collection for partition2...");
130 let freed = heap.garbage_collect(partition2, GcHeap::DUMMY_DISPOSE_CALLBACK);
131 println!(" Collected {} bytes", freed);
132
133 // Verify partition2 root objects are still valid
134 println!("\nVerify partition2 root objects are still valid:");
135 println!(" Object4: '{}'", unsafe { obj4.as_ref() });
136
137 // Trigger garbage collection for partition1 again to collect unreferenced objects
138 println!("\nTrigger garbage collection for partition1 again...");
139 // obj2 is no longer explicitly un-rooted, but we can simulate it going out of scope
140 // to test collection. For this example, we'll just collect other garbage.
141 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
142 println!(" Collected {} bytes", freed);
143
144 // Verify remaining root objects are still valid
145 println!("\nVerify remaining root objects are still valid:");
146 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
147 println!(" Object2: {} (still a root)", unsafe { obj2.as_ref() });
148
149 // Demonstrate automatic garbage collection
150 println!("\nDemonstrate automatic garbage collection...");
151
152 // Create a small partition to demonstrate automatic GC
153 let small_partition = heap.create_partition(64 * 1024, 16 * 1024);
154
155 // Allocate multiple objects to fill partition
156 for i in 0..5 {
157 let _obj = unsafe { heap.alloc_raw(small_partition, MyString(format!("Object {}", i))) }
158 .map_err(|(err, _)| err)?;
159 }
160
161 println!(" Allocated 5 objects in small partition");
162
163 // Demonstrate weak references
164 println!("\nDemonstrate weak references:");
165 let weak_ref = heap.downgrade(&obj1);
166 println!(" Created weak reference: {:?}", weak_ref);
167
168 // Upgrade weak reference
169 match weak_ref.upgrade(&heap) {
170 Some(strong_ref) => {
171 println!(" Weak reference upgrade successful: '{}'", &*strong_ref);
172 }
173 None => {
174 println!(" Weak reference upgrade failed");
175 }
176 }
177
178 // Demonstrate complex types with GC references
179 println!("\nDemonstrate complex types with GC references:");
180 let mut node1 =
181 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 1")) }.map_err(|(err, _)| err)?;
182 let mut node2 =
183 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 2")) }.map_err(|(err, _)| err)?;
184
185 // Establish references between nodes
186 {
187 unsafe {
188 node1.with_write_barrier(&mut heap, |n| n.add_child(node2));
189 }
190 unsafe {
191 node2.with_write_barrier(&mut heap, |n| n.add_child(node1));
192 }
193 }
194
195 println!(" Created node1: {}", unsafe { node1.as_ref() });
196 println!(" Created node2: {}", unsafe { node2.as_ref() });
197
198 // Trigger garbage collection, verify circular references are handled correctly
199 println!("\nGarbage collection for handling circular references...");
200 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
201 println!(" 回收了 {} 字节内存", freed);
202
203 // Demonstrate partition deletion
204 println!("\nDemonstrate partition deletion:");
205
206 // Create an empty partition
207 let empty_partition = heap.create_partition(64 * 1024, 16 * 1024);
208 println!(" Created empty partition: {:?}", empty_partition);
209
210 // Delete empty partition
211 heap.remove_partition(empty_partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
212 println!(" Deleted empty partition successfully");
213
214 // Delete non-empty partition
215 heap.remove_partition(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
216 println!(" Deleted non-empty partition successfully");
217
218 println!("\nExample completed!");
219 Ok(())
220}Source§impl GcHeap
impl GcHeap
Sourcepub unsafe fn alloc_raw<T: GcNode>(
&mut self,
partition_id: GcPartitionId,
payload: T,
) -> Result<GcRef<T>, (GcError, T)>
pub unsafe fn alloc_raw<T: GcNode>( &mut self, partition_id: GcPartitionId, payload: T, ) -> Result<GcRef<T>, (GcError, T)>
Allocate a typed gc node with payload data, do not put to any scope, even if the current scope is present.
§SAFETY
This function is unsafe because it directly manipulates raw pointers and memory allocation.
The caller must ensure that the partition_id is valid and that the returned GcRef is
properly managed to avoid memory leaks or use-after-free errors.
Examples found in repository?
38fn benchmark_object_sizes() {
39 let sizes = [10, 100, 500, 1000, 5000];
40
41 for &size in &sizes {
42 println!("\nTest object count: {}", size);
43
44 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
45 let partition = context.create_partition(64 * 1024, 16 * 1024);
46
47 // Measure allocation performance
48 let alloc_start = Instant::now();
49 let mut objects = Vec::new();
50 for _i in 0..size {
51 let node = unsafe {
52 context.alloc_raw(
53 partition,
54 SimpleNode {
55 _data: vec![0u8; 100],
56 },
57 )
58 } // Each node 100 bytes
59 .unwrap();
60 objects.push(node);
61 }
62 let alloc_duration = alloc_start.elapsed();
63
64 println!(" Allocated {} objects in: {:?}", size, alloc_duration);
65 println!(
66 " Average allocation time per object: {:?}",
67 alloc_duration / size as u32
68 );
69
70 // Measure GC performance (all objects can be collected)
71 let gc_start = Instant::now();
72 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
73 let gc_duration = gc_start.elapsed();
74
75 println!(" GC回收 {} 字节耗时: {:?}", freed, gc_duration);
76 println!(
77 " Average collection time per byte: {:?}",
78 if freed > 0 {
79 gc_duration / freed as u32
80 } else {
81 Duration::from_nanos(0)
82 }
83 );
84 }
85}
86
87/// Test GC performance of complex object graphs
88fn benchmark_complex_graphs() {
89 let sizes = [100, 500, 1000];
90
91 for &size in &sizes {
92 println!("\nTest complex object graph size: {} nodes", size);
93
94 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
95 let partition = context.create_partition(64 * 1024, 16 * 1024);
96
97 // Create complex object graph
98 let graph_start = Instant::now();
99 let mut nodes = Vec::new();
100
101 // Create all nodes
102 for _i in 0..size {
103 let node = unsafe {
104 context.alloc_raw(
105 partition,
106 GraphNode {
107 neighbors: Vec::new(),
108 },
109 )
110 }
111 .unwrap();
112 nodes.push(node);
113 }
114
115 // Establish complex dependencies
116 for i in 0..size {
117 {
118 // Each node points to subsequent nodes
119 for j in 1..=5 {
120 if i + j < size {
121 let n = nodes[i + j];
122 unsafe {
123 nodes[i]
124 .with_write_barrier(&mut context, |node| node.neighbors.push(n));
125 }
126 }
127 }
128 // Every 10 nodes form a cycle
129 if i % 10 == 0 && i + 9 < size {
130 let n = nodes[i];
131 unsafe {
132 nodes[i + 9]
133 .with_write_barrier(&mut context, |node| node.neighbors.push(n));
134 }
135 }
136 }
137 }
138 let graph_duration = graph_start.elapsed();
139
140 println!(" Built complex object graph in: {:?}", graph_duration);
141
142 // Measure GC performance
143 let gc_start = Instant::now();
144 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
145 let gc_duration = gc_start.elapsed();
146
147 println!(" GC回收 {} 字节耗时: {:?}", freed, gc_duration);
148 println!(
149 " Object graph complexity: average {} neighbors per node",
150 if size > 0 { (size * 5) / size } else { 0 }
151 );
152 }
153}
154
155/// Test memory usage efficiency
156fn benchmark_memory_efficiency() {
157 println!("\nTesting memory usage efficiency...");
158
159 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
160 context.set_memory_limit(1024 * 1024); // 1MB global limit
161 let partition = context.create_partition(64 * 1024, 16 * 1024);
162
163 // Allocate many small objects
164 let small_objects_count = 1000;
165 let mut small_objects = Vec::new();
166
167 for _i in 0..small_objects_count {
168 let obj = unsafe { context.alloc_raw(partition, SmallData {}) }.unwrap();
169 small_objects.push(obj);
170 }
171
172 if let Some(partition_info) = context.partition(partition) {
173 let used = partition_info.memory_used();
174 let limit = context.memory_limit();
175 let efficiency = if limit > 0 {
176 (used as f64 / limit as f64) * 100.0
177 } else {
178 0.0
179 };
180
181 println!(" After allocating {} small objects:", small_objects_count);
182 println!(
183 " Memory usage: {}/{} bytes ({:.1}%)",
184 used, limit, efficiency
185 );
186 println!(
187 " Average overhead per object: {} bytes",
188 if small_objects_count > 0 {
189 used / small_objects_count
190 } else {
191 0
192 }
193 );
194 }
195
196 // Collect all objects
197 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
198 println!(" Collected all objects, freed {} bytes", freed);
199
200 // Verify complete memory collection
201 if let Some(partition_info) = context.partition(partition) {
202 let used_after = partition_info.memory_used();
203 println!(" Memory usage after collection: {} bytes", used_after);
204 println!(
205 " Memory collection rate: {:.1}%",
206 if freed > 0 {
207 (freed as f64 / (freed + used_after) as f64) * 100.0
208 } else {
209 0.0
210 }
211 );
212 }
213}
214
215/// Test automatic GC threshold performance
216fn benchmark_auto_gc_threshold() {
217 println!("\nTesting automatic GC threshold performance...");
218
219 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
220 context.set_memory_limit(2048); // 2KB global limit
221 let partition = context.create_partition(64 * 1024, 16 * 1024);
222
223 // Set automatic GC threshold to 1.5KB
224 context.set_gc_threshold(1500);
225
226 // Allocate objects until automatic GC is triggered
227 let mut allocated_bytes = 0;
228 let mut object_count = 0;
229
230 println!(" Allocating objects until automatic GC is triggered...");
231
232 for _i in 0..100 {
233 // Try at most 100 times
234 // Allocate objects of about 100 bytes
235 let node = SimpleNode {
236 _data: vec![0u8; 100],
237 };
238 match unsafe { context.alloc_raw(partition, node) } {
239 Ok(_gc_ref) => {
240 allocated_bytes += 100 + std::mem::size_of::<GcRef<SimpleNode>>(); // Estimated size
241 object_count += 1;
242
243 // Check if approaching threshold
244 if let Some(partition_info) = context.partition(partition)
245 && partition_info.memory_used() >= 1500
246 {
247 println!(
248 " Reached automatic GC threshold, allocated {} objects",
249 object_count
250 );
251 println!(" Estimated allocated memory: {} bytes", allocated_bytes);
252 println!(
253 " Actual memory usage: {} bytes",
254 partition_info.memory_used()
255 );
256 break;
257 }
258 }
259 Err(_) => {
260 println!(" Allocation failed, automatic GC may have been triggered");
261 break;
262 }
263 }
264 }
265
266 // Manually trigger GC to see effect
267 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
268 println!(" Manual GC freed {} bytes", freed);
269}More examples
34fn demonstrate_out_of_memory() -> GcResult<()> {
35 println!("1. Create limited memory partition...");
36
37 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
38 context.set_memory_limit(2048); // 2KB global limit
39 let partition_id = context.create_partition(64 * 1024, 16 * 1024);
40
41 // Allocate first large object (1KB + header)
42 println!("2. Allocate first large object...");
43 let gc1: GcRef<LargeData> =
44 match unsafe { context.alloc_raw(partition_id, LargeData { data: [0; 1024] }) } {
45 Ok(gc_ref) => {
46 println!(" ✓ Successfully allocated first object (1KB)");
47 gc_ref
48 }
49 Err((error, _)) => {
50 println!(" ✗ First object allocation failed: {:?}", error);
51 return Ok(());
52 }
53 };
54
55 // Allocate second large object (1KB + header) - should exceed 2KB limit
56 println!("3. Try to allocate second large object...");
57 match unsafe { context.alloc_raw(partition_id, LargeData { data: [0; 1024] }) } {
58 Err((GcError::PartitionFull, _)) => {
59 println!(" ✓ Correctly detected partition full error");
60 }
61 Ok(_) => {
62 println!(" ✗ Expected partition full error, but allocation succeeded");
63 return Ok(());
64 }
65 Err((other_error, _)) => {
66 println!(
67 " ✗ Expected partition full error, but got: {:?}",
68 other_error
69 );
70 return Ok(());
71 }
72 }
73
74 // Clean up - through garbage collection instead of manual release
75 println!(" ✓ Automatic cleanup through GC");
76 context.garbage_collect(partition_id, GcHeap::DUMMY_DISPOSE_CALLBACK);
77
78 Ok(())
79}
80
81/// Demonstrate partition management errors
82fn demonstrate_partition_management_errors() -> GcResult<()> {
83 println!("1. Test non-existent partition operations...");
84
85 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
86 let invalid_partition = gc_lite::GcPartitionId(9999); // Non-existent partition
87
88 // Test allocating objects in non-existent partition
89 match unsafe {
90 context.alloc_raw(
91 invalid_partition,
92 TestData {
93 value: 42,
94 name: "test".to_string(),
95 },
96 )
97 } {
98 Err((GcError::PartitionNotFound, _)) => {
99 println!(" ✓ Allocating objects in non-existent partition returns correct error");
100 }
101 Ok(_) => {
102 println!(" ✗ Expected partition not found error, but allocation succeeded");
103 }
104 Err((other_error, _)) => {
105 println!(
106 " ✗ Expected partition not found error, but got: {:?}",
107 other_error
108 );
109 }
110 }
111
112 // Test getting non-existent partition information
113 let partition_info = context.partition(invalid_partition);
114 assert!(
115 partition_info.is_none(),
116 "Non-existent partition should return None"
117 );
118 println!(" ✓ Getting non-existent partition info returns None");
119
120 // Test removing non-existent partition (remove_partition doesn't return error, just silently fails)
121 context.remove_partition(invalid_partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
122 println!(" ✓ Removing non-existent partition silently fails");
123
124 println!("\n2. Test non-empty partition deletion...");
125 let partition_id = context.create_partition(64 * 1024, 16 * 1024);
126
127 // Allocate objects in partition
128 let obj = unsafe {
129 context.alloc_raw(
130 partition_id,
131 TestData {
132 value: 1,
133 name: "obj".to_string(),
134 },
135 )
136 }
137 .unwrap();
138 let _ = obj;
139
140 // Try to delete non-empty partition (remove_partition will force cleanup)
141 context.remove_partition(partition_id, GcHeap::DUMMY_DISPOSE_CALLBACK);
142 println!(" ✓ Successfully deleted non-empty partition (root objects were force cleaned)");
143
144 Ok(())
145}169fn demonstrate_complex_structures(
170 heap: &mut GcHeap,
171 partition: gc_lite::GcPartitionId,
172) -> GcResult<()> {
173 println!("1. Create complex data structures...");
174
175 // Create multiple nodes
176 let mut root_node =
177 unsafe { heap.alloc_root_raw(partition, TreeNode::new("Root")) }.map_err(|(err, _)| err)?;
178 let mut child1 =
179 unsafe { heap.alloc_raw(partition, TreeNode::new("Child 1")) }.map_err(|(err, _)| err)?;
180 let child2 =
181 unsafe { heap.alloc_raw(partition, TreeNode::new("Child 2")) }.map_err(|(err, _)| err)?;
182 let grandchild = unsafe { heap.alloc_raw(partition, TreeNode::new("Grandchild")) }
183 .map_err(|(err, _)| err)?;
184
185 // Build tree structure
186 {
187 unsafe {
188 root_node.with_write_barrier(heap, |n| n.add_child(child1));
189 }
190 unsafe {
191 root_node.with_write_barrier(heap, |n| n.add_child(child2));
192 }
193 unsafe {
194 child1.with_write_barrier(heap, |n| n.add_child(grandchild));
195 }
196 }
197
198 // Create data container
199 let container = unsafe {
200 heap.alloc_root_raw(
201 partition,
202 DataContainer {
203 root: root_node,
204 metadata: vec![1, 2, 3],
205 optional_data: Some(child1),
206 },
207 )
208 }
209 .map_err(|(err, _)| err)?;
210
211 println!(" Created tree structure:");
212 println!(" Root -> Child 1 -> Grandchild");
213 println!(" Root -> Child 2");
214 println!(" Created data container");
215
216 // Trigger garbage collection
217 println!("\n2. Trigger garbage collection...");
218 let freed = heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
219 println!(" 回收了 {} 字节内存", freed);
220
221 // Verify data structure integrity
222 println!("\n3. Verify data structure integrity...");
223 {
224 let container_ref = unsafe { container.as_ref() };
225 println!(
226 " Container root node: {}",
227 unsafe { container_ref.root.as_ref() }.name
228 );
229 println!(" Metadata length: {}", container_ref.metadata.len());
230 println!(
231 " Optional data exists: {}",
232 container_ref.optional_data.is_some()
233 );
234 }
235
236 Ok(())
237}
238
239/// Demonstrate reference recovery functionality
240fn demonstrate_reference_recovery(
241 heap: &mut GcHeap,
242 partition: gc_lite::GcPartitionId,
243) -> GcResult<()> {
244 println!("1. Create object and get reference...");
245
246 let original_ref = unsafe {
247 heap.alloc_raw(
248 partition,
249 TestData {
250 value: 42,
251 name: "test".to_string(),
252 },
253 )
254 }
255 .map_err(|(err, _)| err)?;
256
257 let data_ref = unsafe { original_ref.as_ref() };
258 println!(" Original reference: {:?}", original_ref);
259 println!(" Data: {:?}", data_ref);
260
261 // Recover GcRef from reference
262 println!("\n2. Recover GcRef from reference...");
263 let recovered_ref = unsafe { GcRef::try_from_ref(heap, data_ref) };
264
265 match recovered_ref {
266 Some(recovered) => {
267 println!(" Recovery successful: {:?}", recovered);
268 let recovered_data = unsafe { recovered.as_ref() };
269 println!(" Recovered data: {:?}", recovered_data);
270 println!(" Data equal: {}", data_ref == recovered_data);
271 println!(" Reference equal: {}", original_ref == recovered);
272 }
273 None => println!(" Recovery failed (possibly type registration issue)"),
274 }
275
276 // Test invalid reference recovery - create an object not in GC heap
277 println!("\n3. Test invalid reference recovery...");
278 let local_data = TestData {
279 value: 100,
280 name: "local".to_string(),
281 };
282 let invalid_result = unsafe { GcRef::try_from_ref(heap, &local_data) };
283 println!(
284 " Invalid reference recovery result: {:?} (should be None)",
285 invalid_result
286 );
287
288 Ok(())
289}
290
291/// Demonstrate cross-context detection
292fn demonstrate_cross_context_detection() -> GcResult<()> {
293 println!("1. Create two independent heaps...");
294
295 let mut heap1 = new_heap();
296 let mut heap2 = new_heap();
297
298 let partition1 = heap1.create_partition(64 * 1024, 16 * 1024);
299 let partition2 = heap2.create_partition(64 * 1024, 16 * 1024);
300
301 let obj1 = unsafe {
302 heap1.alloc_root_raw(
303 partition1,
304 TestData {
305 value: 1,
306 name: "obj1".to_string(),
307 },
308 )
309 }
310 .map_err(|(e, _)| e)?;
311 let obj2 = unsafe {
312 heap2.alloc_raw(
313 partition2,
314 TestData {
315 value: 2,
316 name: "obj2".to_string(),
317 },
318 )
319 }
320 .map_err(|(e, _)| e)?;
321
322 println!("2. Test object source detection...");
323 assert!(heap1.contains(obj1.node_ptr()), "obj1 should be from heap1");
324 assert!(
325 !heap1.contains(obj2.node_ptr()),
326 "obj2 should not be from heap1"
327 );
328 assert!(heap2.contains(obj2.node_ptr()), "obj2 should be from heap2");
329 assert!(
330 !heap2.contains(obj1.node_ptr()),
331 "obj1 should not be from heap2"
332 );
333
334 println!(" ✓ Cross-context detection correct");
335
336 // Clean up
337 heap1.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
338 heap2.garbage_collect(partition2, GcHeap::DUMMY_DISPOSE_CALLBACK);
339
340 Ok(())
341}47fn main() -> GcResult<()> {
48 println!("=== Basic usage example of partitioned garbage collection system ===");
49
50 // Create garbage collection context
51 let mut heap = GcHeap::new(&GC_TYPE_REGISTRY);
52
53 println!("Initial state:");
54 println!(" Number of partitions: {}", heap.partition_ids().len());
55
56 // Create two partitions
57 println!("\nCreate partitions:");
58 let partition1 = heap.create_partition(64 * 1024, 16 * 1024);
59 let partition2 = heap.create_partition(64 * 1024, 16 * 1024);
60 println!(" Created partition1: {:?}", partition1);
61 println!(" Created partition2: {:?}", partition2);
62 println!(" Number of partitions: {}", heap.partition_ids().len());
63
64 // Allocate objects in partition1
65 println!("\nAllocate objects in partition1:");
66 let obj1 = unsafe { heap.alloc_raw(partition1, MyString(String::from("Hello"))) }
67 .map_err(|(err, _)| err)?;
68 let obj2 = unsafe { heap.alloc_raw(partition1, MyI32(42)) }.map_err(|(err, _)| err)?;
69 let obj3 = unsafe { heap.alloc_raw(partition1, MyString(String::from("VectorData"))) }
70 .map_err(|(err, _)| err)?;
71
72 println!(" Created string: '{}'", unsafe { obj1.as_ref() });
73 println!(" Created number: {}", unsafe { obj2.as_ref() });
74 println!(" Created string: '{}'", unsafe { obj3.as_ref() });
75
76 // Allocate objects in partition2
77 println!("\nAllocate objects in partition2:");
78 let obj4 = unsafe { heap.alloc_raw(partition2, MyString(String::from("World"))) }
79 .map_err(|(err, _)| err)?;
80 let obj5 = unsafe { heap.alloc_raw(partition2, MyI32(99)) }.map_err(|(err, _)| err)?;
81
82 println!(" Created string: '{}'", unsafe { obj4.as_ref() });
83 println!(" Created number: {}", unsafe { obj5.as_ref() });
84
85 // Display partition status
86 println!("\nPartition status:");
87 for partition_id in heap.partition_ids() {
88 if let Some(partition) = heap.partition(partition_id) {
89 let limit = heap.memory_limit();
90 let usage = if limit > 0 {
91 format!(
92 "{}/{} bytes ({:.1}%)",
93 partition.memory_used(),
94 limit,
95 (partition.memory_used() as f64 / limit as f64) * 100.0
96 )
97 } else {
98 format!("{}/∞ bytes", partition.memory_used())
99 };
100 println!(
101 " {:?}: {} [自动GC: {}]",
102 partition_id,
103 usage,
104 if heap.gc_threshold() > 0 {
105 "Enabled"
106 } else {
107 "Disabled"
108 }
109 );
110 }
111 }
112
113 // Root objects are now implicitly managed by stack variables (e.g., obj1, obj2).
114 // No explicit `set_root` calls are needed for them.
115 println!("\nRoot objects are held by variables:");
116 println!(" Roots: obj1, obj2, obj3, obj4, obj5");
117
118 // Manually trigger garbage collection for partition1
119 println!("\nManually trigger garbage collection for partition1...");
120 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
121 println!(" Collected {} bytes", freed);
122
123 // Verify root objects are still valid
124 println!("\nVerify partition1 root objects are still valid:");
125 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
126 println!(" Object2: {}", unsafe { obj2.as_ref() });
127
128 // Manually trigger garbage collection for partition2
129 println!("\nManually trigger garbage collection for partition2...");
130 let freed = heap.garbage_collect(partition2, GcHeap::DUMMY_DISPOSE_CALLBACK);
131 println!(" Collected {} bytes", freed);
132
133 // Verify partition2 root objects are still valid
134 println!("\nVerify partition2 root objects are still valid:");
135 println!(" Object4: '{}'", unsafe { obj4.as_ref() });
136
137 // Trigger garbage collection for partition1 again to collect unreferenced objects
138 println!("\nTrigger garbage collection for partition1 again...");
139 // obj2 is no longer explicitly un-rooted, but we can simulate it going out of scope
140 // to test collection. For this example, we'll just collect other garbage.
141 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
142 println!(" Collected {} bytes", freed);
143
144 // Verify remaining root objects are still valid
145 println!("\nVerify remaining root objects are still valid:");
146 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
147 println!(" Object2: {} (still a root)", unsafe { obj2.as_ref() });
148
149 // Demonstrate automatic garbage collection
150 println!("\nDemonstrate automatic garbage collection...");
151
152 // Create a small partition to demonstrate automatic GC
153 let small_partition = heap.create_partition(64 * 1024, 16 * 1024);
154
155 // Allocate multiple objects to fill partition
156 for i in 0..5 {
157 let _obj = unsafe { heap.alloc_raw(small_partition, MyString(format!("Object {}", i))) }
158 .map_err(|(err, _)| err)?;
159 }
160
161 println!(" Allocated 5 objects in small partition");
162
163 // Demonstrate weak references
164 println!("\nDemonstrate weak references:");
165 let weak_ref = heap.downgrade(&obj1);
166 println!(" Created weak reference: {:?}", weak_ref);
167
168 // Upgrade weak reference
169 match weak_ref.upgrade(&heap) {
170 Some(strong_ref) => {
171 println!(" Weak reference upgrade successful: '{}'", &*strong_ref);
172 }
173 None => {
174 println!(" Weak reference upgrade failed");
175 }
176 }
177
178 // Demonstrate complex types with GC references
179 println!("\nDemonstrate complex types with GC references:");
180 let mut node1 =
181 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 1")) }.map_err(|(err, _)| err)?;
182 let mut node2 =
183 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 2")) }.map_err(|(err, _)| err)?;
184
185 // Establish references between nodes
186 {
187 unsafe {
188 node1.with_write_barrier(&mut heap, |n| n.add_child(node2));
189 }
190 unsafe {
191 node2.with_write_barrier(&mut heap, |n| n.add_child(node1));
192 }
193 }
194
195 println!(" Created node1: {}", unsafe { node1.as_ref() });
196 println!(" Created node2: {}", unsafe { node2.as_ref() });
197
198 // Trigger garbage collection, verify circular references are handled correctly
199 println!("\nGarbage collection for handling circular references...");
200 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
201 println!(" 回收了 {} 字节内存", freed);
202
203 // Demonstrate partition deletion
204 println!("\nDemonstrate partition deletion:");
205
206 // Create an empty partition
207 let empty_partition = heap.create_partition(64 * 1024, 16 * 1024);
208 println!(" Created empty partition: {:?}", empty_partition);
209
210 // Delete empty partition
211 heap.remove_partition(empty_partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
212 println!(" Deleted empty partition successfully");
213
214 // Delete non-empty partition
215 heap.remove_partition(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
216 println!(" Deleted non-empty partition successfully");
217
218 println!("\nExample completed!");
219 Ok(())
220}Sourcepub unsafe fn alloc_root_raw<T: GcNode>(
&mut self,
partition_id: GcPartitionId,
payload: T,
) -> Result<GcRef<T>, (GcError, T)>
pub unsafe fn alloc_root_raw<T: GcNode>( &mut self, partition_id: GcPartitionId, payload: T, ) -> Result<GcRef<T>, (GcError, T)>
Allocate a root node — bypasses arena directly to system malloc.
Root nodes are permanent and should not waste arena space.
§SAFETY
This function is unsafe because it directly manipulates raw pointers and memory allocation.
The caller must ensure that the partition_id is valid and that the returned GcRef is
properly managed to avoid memory leaks or use-after-free errors.
Examples found in repository?
76fn demonstrate_weak_references(
77 heap: &mut GcHeap,
78 partition: gc_lite::GcPartitionId,
79) -> GcResult<()> {
80 println!("1. Create strong and weak references...");
81
82 let strong_ref =
83 unsafe { heap.alloc_root_raw(partition, MyString(String::from("Strong Reference Data"))) }
84 .map_err(|(err, _)| err)?;
85
86 let weak_ref = heap.downgrade(&strong_ref);
87 println!(" Created strong reference: {:?}", strong_ref);
88 println!(" Created weak reference: {:?}", weak_ref);
89
90 // Upgrade weak reference
91 println!("\n2. Upgrade weak reference...");
92 match weak_ref.upgrade(heap) {
93 Some(upgraded) => {
94 let data = &*upgraded;
95 println!(" Weak reference upgrade successful: '{}'", data);
96 assert_eq!(data, "Strong Reference Data");
97 }
98 None => println!(" Weak reference upgrade failed"),
99 }
100
101 // Try upgrading after releasing strong reference
102 println!("\n3. Upgrade weak reference after releasing strong reference...");
103 heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
104
105 match weak_ref.upgrade(heap) {
106 Some(_) => {
107 println!(" Weak reference can still be upgraded (object may still be in memory)")
108 }
109 None => println!(" Weak reference upgrade failed (object has been collected)"),
110 }
111
112 Ok(())
113}
114
115/// Demonstrate circular reference handling
116fn demonstrate_cyclic_references(
117 heap: &mut GcHeap,
118 partition: gc_lite::GcPartitionId,
119) -> GcResult<()> {
120 println!("1. Create circular reference nodes...");
121
122 // Create two mutually referencing nodes
123 let mut node1 = unsafe { heap.alloc_root_raw(partition, CyclicNode::new("Node A")) }
124 .map_err(|(err, _)| err)?;
125 let mut node2 = unsafe { heap.alloc_root_raw(partition, CyclicNode::new("Node B")) }
126 .map_err(|(err, _)| err)?;
127
128 // Establish circular references
129 {
130 unsafe {
131 node1.with_write_barrier(heap, |n| n.set_partner(node2));
132 }
133 unsafe {
134 node2.with_write_barrier(heap, |n| n.set_partner(node1));
135 }
136 }
137
138 println!(" Created node1: {}", unsafe { node1.as_ref() });
139 println!(" Created node2: {}", unsafe { node2.as_ref() });
140
141 // Trigger garbage collection
142 println!("\n2. Trigger garbage collection (circular references still exist)...");
143 let freed = heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
144 println!(" 回收了 {} 字节内存", freed);
145
146 // Verify circular references still exist
147 println!("\n3. Verify circular references...");
148 println!(
149 " Node1's partner: {}",
150 unsafe { node1.as_ref() }.get_partner_name()
151 );
152 println!(
153 " Node2's partner: {}",
154 unsafe { node2.as_ref() }.get_partner_name()
155 );
156
157 // Clear root object status, let circular references be collected
158 println!("\n4. Clear root object status and trigger GC again...");
159 let freed = heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
160 println!(
161 " Freed {} bytes of memory (circular references correctly collected)",
162 freed
163 );
164
165 Ok(())
166}
167
168/// Demonstrate complex data structures
169fn demonstrate_complex_structures(
170 heap: &mut GcHeap,
171 partition: gc_lite::GcPartitionId,
172) -> GcResult<()> {
173 println!("1. Create complex data structures...");
174
175 // Create multiple nodes
176 let mut root_node =
177 unsafe { heap.alloc_root_raw(partition, TreeNode::new("Root")) }.map_err(|(err, _)| err)?;
178 let mut child1 =
179 unsafe { heap.alloc_raw(partition, TreeNode::new("Child 1")) }.map_err(|(err, _)| err)?;
180 let child2 =
181 unsafe { heap.alloc_raw(partition, TreeNode::new("Child 2")) }.map_err(|(err, _)| err)?;
182 let grandchild = unsafe { heap.alloc_raw(partition, TreeNode::new("Grandchild")) }
183 .map_err(|(err, _)| err)?;
184
185 // Build tree structure
186 {
187 unsafe {
188 root_node.with_write_barrier(heap, |n| n.add_child(child1));
189 }
190 unsafe {
191 root_node.with_write_barrier(heap, |n| n.add_child(child2));
192 }
193 unsafe {
194 child1.with_write_barrier(heap, |n| n.add_child(grandchild));
195 }
196 }
197
198 // Create data container
199 let container = unsafe {
200 heap.alloc_root_raw(
201 partition,
202 DataContainer {
203 root: root_node,
204 metadata: vec![1, 2, 3],
205 optional_data: Some(child1),
206 },
207 )
208 }
209 .map_err(|(err, _)| err)?;
210
211 println!(" Created tree structure:");
212 println!(" Root -> Child 1 -> Grandchild");
213 println!(" Root -> Child 2");
214 println!(" Created data container");
215
216 // Trigger garbage collection
217 println!("\n2. Trigger garbage collection...");
218 let freed = heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
219 println!(" 回收了 {} 字节内存", freed);
220
221 // Verify data structure integrity
222 println!("\n3. Verify data structure integrity...");
223 {
224 let container_ref = unsafe { container.as_ref() };
225 println!(
226 " Container root node: {}",
227 unsafe { container_ref.root.as_ref() }.name
228 );
229 println!(" Metadata length: {}", container_ref.metadata.len());
230 println!(
231 " Optional data exists: {}",
232 container_ref.optional_data.is_some()
233 );
234 }
235
236 Ok(())
237}
238
239/// Demonstrate reference recovery functionality
240fn demonstrate_reference_recovery(
241 heap: &mut GcHeap,
242 partition: gc_lite::GcPartitionId,
243) -> GcResult<()> {
244 println!("1. Create object and get reference...");
245
246 let original_ref = unsafe {
247 heap.alloc_raw(
248 partition,
249 TestData {
250 value: 42,
251 name: "test".to_string(),
252 },
253 )
254 }
255 .map_err(|(err, _)| err)?;
256
257 let data_ref = unsafe { original_ref.as_ref() };
258 println!(" Original reference: {:?}", original_ref);
259 println!(" Data: {:?}", data_ref);
260
261 // Recover GcRef from reference
262 println!("\n2. Recover GcRef from reference...");
263 let recovered_ref = unsafe { GcRef::try_from_ref(heap, data_ref) };
264
265 match recovered_ref {
266 Some(recovered) => {
267 println!(" Recovery successful: {:?}", recovered);
268 let recovered_data = unsafe { recovered.as_ref() };
269 println!(" Recovered data: {:?}", recovered_data);
270 println!(" Data equal: {}", data_ref == recovered_data);
271 println!(" Reference equal: {}", original_ref == recovered);
272 }
273 None => println!(" Recovery failed (possibly type registration issue)"),
274 }
275
276 // Test invalid reference recovery - create an object not in GC heap
277 println!("\n3. Test invalid reference recovery...");
278 let local_data = TestData {
279 value: 100,
280 name: "local".to_string(),
281 };
282 let invalid_result = unsafe { GcRef::try_from_ref(heap, &local_data) };
283 println!(
284 " Invalid reference recovery result: {:?} (should be None)",
285 invalid_result
286 );
287
288 Ok(())
289}
290
291/// Demonstrate cross-context detection
292fn demonstrate_cross_context_detection() -> GcResult<()> {
293 println!("1. Create two independent heaps...");
294
295 let mut heap1 = new_heap();
296 let mut heap2 = new_heap();
297
298 let partition1 = heap1.create_partition(64 * 1024, 16 * 1024);
299 let partition2 = heap2.create_partition(64 * 1024, 16 * 1024);
300
301 let obj1 = unsafe {
302 heap1.alloc_root_raw(
303 partition1,
304 TestData {
305 value: 1,
306 name: "obj1".to_string(),
307 },
308 )
309 }
310 .map_err(|(e, _)| e)?;
311 let obj2 = unsafe {
312 heap2.alloc_raw(
313 partition2,
314 TestData {
315 value: 2,
316 name: "obj2".to_string(),
317 },
318 )
319 }
320 .map_err(|(e, _)| e)?;
321
322 println!("2. Test object source detection...");
323 assert!(heap1.contains(obj1.node_ptr()), "obj1 should be from heap1");
324 assert!(
325 !heap1.contains(obj2.node_ptr()),
326 "obj2 should not be from heap1"
327 );
328 assert!(heap2.contains(obj2.node_ptr()), "obj2 should be from heap2");
329 assert!(
330 !heap2.contains(obj1.node_ptr()),
331 "obj1 should not be from heap2"
332 );
333
334 println!(" ✓ Cross-context detection correct");
335
336 // Clean up
337 heap1.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
338 heap2.garbage_collect(partition2, GcHeap::DUMMY_DISPOSE_CALLBACK);
339
340 Ok(())
341}Source§impl GcHeap
impl GcHeap
Sourcepub fn bind(&mut self, master: NonNull<GcHead>, slave: NonNull<GcHead>)
pub fn bind(&mut self, master: NonNull<GcHead>, slave: NonNull<GcHead>)
Establishes a directed reference from master to slave and performs
the necessary write barrier for tri-color incremental GC.
§When to use
Call this whenever a GC node (master) starts referencing another GC
node (slave) through a pointer write, e.g.:
- Setting an object property to an object/string value
- Pushing an element into an array
- Storing a result value into a Promise
- Updating a closure variable reference
§Write barrier semantics
In tri-color marking, if master is already Black (fully traced)
and slave is White (not yet traced), the slave would be
incorrectly swept as garbage. This method prevents that by:
- Checking the colors of
masterandslave. - If
masteris Black andslaveis White/Gray, markingslaveas Gray and enqueuing it into the gray list of its partition, ensuring it will be traced in the current GC cycle.
§Safety
Both pointers must point to valid, live GC nodes managed by this heap.
Source§impl GcHeap
impl GcHeap
Sourcepub fn create_partition(
&mut self,
arena_capacity: usize,
arena_max_alloc: usize,
) -> GcPartitionId
pub fn create_partition( &mut self, arena_capacity: usize, arena_max_alloc: usize, ) -> GcPartitionId
Create a new partition and return its ID.
§Parameters
arena_capacity: arena size in bytes.0= disable arena for this partition.arena_max_alloc: allocations larger than this skip the arena.
Examples found in repository?
56fn main() -> GcResult<()> {
57 let mut heap = GcHeap::new(&GC_TYPE_REGISTRY);
58 let partition = heap.create_partition(64 * 1024, 16 * 1024);
59 let stack_id = heap.acquire_scope_stack(partition);
60
61 let static_ref = alloc_static(&mut heap, stack_id, 10)?;
62 let other_ref = alloc_other(&mut heap, stack_id, 20)?;
63
64 println!(
65 "Static node value: {}",
66 unsafe { static_ref.as_ref() }._value
67 );
68 println!("Other node value: {}", unsafe { other_ref.as_ref() }._value);
69
70 heap.release_scope_stack(stack_id);
71
72 println!("gc_node_usage example verified");
73
74 Ok(())
75}More examples
45fn main() -> GcResult<()> {
46 println!("=== Advanced features example of partitioned garbage collection system ===");
47
48 let mut heap = new_heap();
49 let partition = heap.create_partition(64 * 1024, 16 * 1024);
50
51 // Demonstrate weak reference functionality
52 println!("\n=== Weak reference functionality demonstration ===");
53 demonstrate_weak_references(&mut heap, partition)?;
54
55 // Demonstrate circular reference handling
56 println!("\n=== Circular reference handling demonstration ===");
57 demonstrate_cyclic_references(&mut heap, partition)?;
58
59 // Demonstrate complex data structures
60 println!("\n=== Complex data structures demonstration ===");
61 demonstrate_complex_structures(&mut heap, partition)?;
62
63 // Demonstrate reference recovery functionality
64 println!("\n=== Reference recovery functionality demonstration ===");
65 demonstrate_reference_recovery(&mut heap, partition)?;
66
67 // Demonstrate cross-context detection
68 println!("\n=== Cross-context detection demonstration ===");
69 demonstrate_cross_context_detection()?;
70
71 println!("\nAll advanced feature demonstrations completed!");
72 Ok(())
73}
74
75/// Demonstrate weak reference functionality
76fn demonstrate_weak_references(
77 heap: &mut GcHeap,
78 partition: gc_lite::GcPartitionId,
79) -> GcResult<()> {
80 println!("1. Create strong and weak references...");
81
82 let strong_ref =
83 unsafe { heap.alloc_root_raw(partition, MyString(String::from("Strong Reference Data"))) }
84 .map_err(|(err, _)| err)?;
85
86 let weak_ref = heap.downgrade(&strong_ref);
87 println!(" Created strong reference: {:?}", strong_ref);
88 println!(" Created weak reference: {:?}", weak_ref);
89
90 // Upgrade weak reference
91 println!("\n2. Upgrade weak reference...");
92 match weak_ref.upgrade(heap) {
93 Some(upgraded) => {
94 let data = &*upgraded;
95 println!(" Weak reference upgrade successful: '{}'", data);
96 assert_eq!(data, "Strong Reference Data");
97 }
98 None => println!(" Weak reference upgrade failed"),
99 }
100
101 // Try upgrading after releasing strong reference
102 println!("\n3. Upgrade weak reference after releasing strong reference...");
103 heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
104
105 match weak_ref.upgrade(heap) {
106 Some(_) => {
107 println!(" Weak reference can still be upgraded (object may still be in memory)")
108 }
109 None => println!(" Weak reference upgrade failed (object has been collected)"),
110 }
111
112 Ok(())
113}
114
115/// Demonstrate circular reference handling
116fn demonstrate_cyclic_references(
117 heap: &mut GcHeap,
118 partition: gc_lite::GcPartitionId,
119) -> GcResult<()> {
120 println!("1. Create circular reference nodes...");
121
122 // Create two mutually referencing nodes
123 let mut node1 = unsafe { heap.alloc_root_raw(partition, CyclicNode::new("Node A")) }
124 .map_err(|(err, _)| err)?;
125 let mut node2 = unsafe { heap.alloc_root_raw(partition, CyclicNode::new("Node B")) }
126 .map_err(|(err, _)| err)?;
127
128 // Establish circular references
129 {
130 unsafe {
131 node1.with_write_barrier(heap, |n| n.set_partner(node2));
132 }
133 unsafe {
134 node2.with_write_barrier(heap, |n| n.set_partner(node1));
135 }
136 }
137
138 println!(" Created node1: {}", unsafe { node1.as_ref() });
139 println!(" Created node2: {}", unsafe { node2.as_ref() });
140
141 // Trigger garbage collection
142 println!("\n2. Trigger garbage collection (circular references still exist)...");
143 let freed = heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
144 println!(" 回收了 {} 字节内存", freed);
145
146 // Verify circular references still exist
147 println!("\n3. Verify circular references...");
148 println!(
149 " Node1's partner: {}",
150 unsafe { node1.as_ref() }.get_partner_name()
151 );
152 println!(
153 " Node2's partner: {}",
154 unsafe { node2.as_ref() }.get_partner_name()
155 );
156
157 // Clear root object status, let circular references be collected
158 println!("\n4. Clear root object status and trigger GC again...");
159 let freed = heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
160 println!(
161 " Freed {} bytes of memory (circular references correctly collected)",
162 freed
163 );
164
165 Ok(())
166}
167
168/// Demonstrate complex data structures
169fn demonstrate_complex_structures(
170 heap: &mut GcHeap,
171 partition: gc_lite::GcPartitionId,
172) -> GcResult<()> {
173 println!("1. Create complex data structures...");
174
175 // Create multiple nodes
176 let mut root_node =
177 unsafe { heap.alloc_root_raw(partition, TreeNode::new("Root")) }.map_err(|(err, _)| err)?;
178 let mut child1 =
179 unsafe { heap.alloc_raw(partition, TreeNode::new("Child 1")) }.map_err(|(err, _)| err)?;
180 let child2 =
181 unsafe { heap.alloc_raw(partition, TreeNode::new("Child 2")) }.map_err(|(err, _)| err)?;
182 let grandchild = unsafe { heap.alloc_raw(partition, TreeNode::new("Grandchild")) }
183 .map_err(|(err, _)| err)?;
184
185 // Build tree structure
186 {
187 unsafe {
188 root_node.with_write_barrier(heap, |n| n.add_child(child1));
189 }
190 unsafe {
191 root_node.with_write_barrier(heap, |n| n.add_child(child2));
192 }
193 unsafe {
194 child1.with_write_barrier(heap, |n| n.add_child(grandchild));
195 }
196 }
197
198 // Create data container
199 let container = unsafe {
200 heap.alloc_root_raw(
201 partition,
202 DataContainer {
203 root: root_node,
204 metadata: vec![1, 2, 3],
205 optional_data: Some(child1),
206 },
207 )
208 }
209 .map_err(|(err, _)| err)?;
210
211 println!(" Created tree structure:");
212 println!(" Root -> Child 1 -> Grandchild");
213 println!(" Root -> Child 2");
214 println!(" Created data container");
215
216 // Trigger garbage collection
217 println!("\n2. Trigger garbage collection...");
218 let freed = heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
219 println!(" 回收了 {} 字节内存", freed);
220
221 // Verify data structure integrity
222 println!("\n3. Verify data structure integrity...");
223 {
224 let container_ref = unsafe { container.as_ref() };
225 println!(
226 " Container root node: {}",
227 unsafe { container_ref.root.as_ref() }.name
228 );
229 println!(" Metadata length: {}", container_ref.metadata.len());
230 println!(
231 " Optional data exists: {}",
232 container_ref.optional_data.is_some()
233 );
234 }
235
236 Ok(())
237}
238
239/// Demonstrate reference recovery functionality
240fn demonstrate_reference_recovery(
241 heap: &mut GcHeap,
242 partition: gc_lite::GcPartitionId,
243) -> GcResult<()> {
244 println!("1. Create object and get reference...");
245
246 let original_ref = unsafe {
247 heap.alloc_raw(
248 partition,
249 TestData {
250 value: 42,
251 name: "test".to_string(),
252 },
253 )
254 }
255 .map_err(|(err, _)| err)?;
256
257 let data_ref = unsafe { original_ref.as_ref() };
258 println!(" Original reference: {:?}", original_ref);
259 println!(" Data: {:?}", data_ref);
260
261 // Recover GcRef from reference
262 println!("\n2. Recover GcRef from reference...");
263 let recovered_ref = unsafe { GcRef::try_from_ref(heap, data_ref) };
264
265 match recovered_ref {
266 Some(recovered) => {
267 println!(" Recovery successful: {:?}", recovered);
268 let recovered_data = unsafe { recovered.as_ref() };
269 println!(" Recovered data: {:?}", recovered_data);
270 println!(" Data equal: {}", data_ref == recovered_data);
271 println!(" Reference equal: {}", original_ref == recovered);
272 }
273 None => println!(" Recovery failed (possibly type registration issue)"),
274 }
275
276 // Test invalid reference recovery - create an object not in GC heap
277 println!("\n3. Test invalid reference recovery...");
278 let local_data = TestData {
279 value: 100,
280 name: "local".to_string(),
281 };
282 let invalid_result = unsafe { GcRef::try_from_ref(heap, &local_data) };
283 println!(
284 " Invalid reference recovery result: {:?} (should be None)",
285 invalid_result
286 );
287
288 Ok(())
289}
290
291/// Demonstrate cross-context detection
292fn demonstrate_cross_context_detection() -> GcResult<()> {
293 println!("1. Create two independent heaps...");
294
295 let mut heap1 = new_heap();
296 let mut heap2 = new_heap();
297
298 let partition1 = heap1.create_partition(64 * 1024, 16 * 1024);
299 let partition2 = heap2.create_partition(64 * 1024, 16 * 1024);
300
301 let obj1 = unsafe {
302 heap1.alloc_root_raw(
303 partition1,
304 TestData {
305 value: 1,
306 name: "obj1".to_string(),
307 },
308 )
309 }
310 .map_err(|(e, _)| e)?;
311 let obj2 = unsafe {
312 heap2.alloc_raw(
313 partition2,
314 TestData {
315 value: 2,
316 name: "obj2".to_string(),
317 },
318 )
319 }
320 .map_err(|(e, _)| e)?;
321
322 println!("2. Test object source detection...");
323 assert!(heap1.contains(obj1.node_ptr()), "obj1 should be from heap1");
324 assert!(
325 !heap1.contains(obj2.node_ptr()),
326 "obj2 should not be from heap1"
327 );
328 assert!(heap2.contains(obj2.node_ptr()), "obj2 should be from heap2");
329 assert!(
330 !heap2.contains(obj1.node_ptr()),
331 "obj1 should not be from heap2"
332 );
333
334 println!(" ✓ Cross-context detection correct");
335
336 // Clean up
337 heap1.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
338 heap2.garbage_collect(partition2, GcHeap::DUMMY_DISPOSE_CALLBACK);
339
340 Ok(())
341}38fn benchmark_object_sizes() {
39 let sizes = [10, 100, 500, 1000, 5000];
40
41 for &size in &sizes {
42 println!("\nTest object count: {}", size);
43
44 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
45 let partition = context.create_partition(64 * 1024, 16 * 1024);
46
47 // Measure allocation performance
48 let alloc_start = Instant::now();
49 let mut objects = Vec::new();
50 for _i in 0..size {
51 let node = unsafe {
52 context.alloc_raw(
53 partition,
54 SimpleNode {
55 _data: vec![0u8; 100],
56 },
57 )
58 } // Each node 100 bytes
59 .unwrap();
60 objects.push(node);
61 }
62 let alloc_duration = alloc_start.elapsed();
63
64 println!(" Allocated {} objects in: {:?}", size, alloc_duration);
65 println!(
66 " Average allocation time per object: {:?}",
67 alloc_duration / size as u32
68 );
69
70 // Measure GC performance (all objects can be collected)
71 let gc_start = Instant::now();
72 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
73 let gc_duration = gc_start.elapsed();
74
75 println!(" GC回收 {} 字节耗时: {:?}", freed, gc_duration);
76 println!(
77 " Average collection time per byte: {:?}",
78 if freed > 0 {
79 gc_duration / freed as u32
80 } else {
81 Duration::from_nanos(0)
82 }
83 );
84 }
85}
86
87/// Test GC performance of complex object graphs
88fn benchmark_complex_graphs() {
89 let sizes = [100, 500, 1000];
90
91 for &size in &sizes {
92 println!("\nTest complex object graph size: {} nodes", size);
93
94 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
95 let partition = context.create_partition(64 * 1024, 16 * 1024);
96
97 // Create complex object graph
98 let graph_start = Instant::now();
99 let mut nodes = Vec::new();
100
101 // Create all nodes
102 for _i in 0..size {
103 let node = unsafe {
104 context.alloc_raw(
105 partition,
106 GraphNode {
107 neighbors: Vec::new(),
108 },
109 )
110 }
111 .unwrap();
112 nodes.push(node);
113 }
114
115 // Establish complex dependencies
116 for i in 0..size {
117 {
118 // Each node points to subsequent nodes
119 for j in 1..=5 {
120 if i + j < size {
121 let n = nodes[i + j];
122 unsafe {
123 nodes[i]
124 .with_write_barrier(&mut context, |node| node.neighbors.push(n));
125 }
126 }
127 }
128 // Every 10 nodes form a cycle
129 if i % 10 == 0 && i + 9 < size {
130 let n = nodes[i];
131 unsafe {
132 nodes[i + 9]
133 .with_write_barrier(&mut context, |node| node.neighbors.push(n));
134 }
135 }
136 }
137 }
138 let graph_duration = graph_start.elapsed();
139
140 println!(" Built complex object graph in: {:?}", graph_duration);
141
142 // Measure GC performance
143 let gc_start = Instant::now();
144 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
145 let gc_duration = gc_start.elapsed();
146
147 println!(" GC回收 {} 字节耗时: {:?}", freed, gc_duration);
148 println!(
149 " Object graph complexity: average {} neighbors per node",
150 if size > 0 { (size * 5) / size } else { 0 }
151 );
152 }
153}
154
155/// Test memory usage efficiency
156fn benchmark_memory_efficiency() {
157 println!("\nTesting memory usage efficiency...");
158
159 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
160 context.set_memory_limit(1024 * 1024); // 1MB global limit
161 let partition = context.create_partition(64 * 1024, 16 * 1024);
162
163 // Allocate many small objects
164 let small_objects_count = 1000;
165 let mut small_objects = Vec::new();
166
167 for _i in 0..small_objects_count {
168 let obj = unsafe { context.alloc_raw(partition, SmallData {}) }.unwrap();
169 small_objects.push(obj);
170 }
171
172 if let Some(partition_info) = context.partition(partition) {
173 let used = partition_info.memory_used();
174 let limit = context.memory_limit();
175 let efficiency = if limit > 0 {
176 (used as f64 / limit as f64) * 100.0
177 } else {
178 0.0
179 };
180
181 println!(" After allocating {} small objects:", small_objects_count);
182 println!(
183 " Memory usage: {}/{} bytes ({:.1}%)",
184 used, limit, efficiency
185 );
186 println!(
187 " Average overhead per object: {} bytes",
188 if small_objects_count > 0 {
189 used / small_objects_count
190 } else {
191 0
192 }
193 );
194 }
195
196 // Collect all objects
197 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
198 println!(" Collected all objects, freed {} bytes", freed);
199
200 // Verify complete memory collection
201 if let Some(partition_info) = context.partition(partition) {
202 let used_after = partition_info.memory_used();
203 println!(" Memory usage after collection: {} bytes", used_after);
204 println!(
205 " Memory collection rate: {:.1}%",
206 if freed > 0 {
207 (freed as f64 / (freed + used_after) as f64) * 100.0
208 } else {
209 0.0
210 }
211 );
212 }
213}
214
215/// Test automatic GC threshold performance
216fn benchmark_auto_gc_threshold() {
217 println!("\nTesting automatic GC threshold performance...");
218
219 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
220 context.set_memory_limit(2048); // 2KB global limit
221 let partition = context.create_partition(64 * 1024, 16 * 1024);
222
223 // Set automatic GC threshold to 1.5KB
224 context.set_gc_threshold(1500);
225
226 // Allocate objects until automatic GC is triggered
227 let mut allocated_bytes = 0;
228 let mut object_count = 0;
229
230 println!(" Allocating objects until automatic GC is triggered...");
231
232 for _i in 0..100 {
233 // Try at most 100 times
234 // Allocate objects of about 100 bytes
235 let node = SimpleNode {
236 _data: vec![0u8; 100],
237 };
238 match unsafe { context.alloc_raw(partition, node) } {
239 Ok(_gc_ref) => {
240 allocated_bytes += 100 + std::mem::size_of::<GcRef<SimpleNode>>(); // Estimated size
241 object_count += 1;
242
243 // Check if approaching threshold
244 if let Some(partition_info) = context.partition(partition)
245 && partition_info.memory_used() >= 1500
246 {
247 println!(
248 " Reached automatic GC threshold, allocated {} objects",
249 object_count
250 );
251 println!(" Estimated allocated memory: {} bytes", allocated_bytes);
252 println!(
253 " Actual memory usage: {} bytes",
254 partition_info.memory_used()
255 );
256 break;
257 }
258 }
259 Err(_) => {
260 println!(" Allocation failed, automatic GC may have been triggered");
261 break;
262 }
263 }
264 }
265
266 // Manually trigger GC to see effect
267 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
268 println!(" Manual GC freed {} bytes", freed);
269}34fn demonstrate_out_of_memory() -> GcResult<()> {
35 println!("1. Create limited memory partition...");
36
37 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
38 context.set_memory_limit(2048); // 2KB global limit
39 let partition_id = context.create_partition(64 * 1024, 16 * 1024);
40
41 // Allocate first large object (1KB + header)
42 println!("2. Allocate first large object...");
43 let gc1: GcRef<LargeData> =
44 match unsafe { context.alloc_raw(partition_id, LargeData { data: [0; 1024] }) } {
45 Ok(gc_ref) => {
46 println!(" ✓ Successfully allocated first object (1KB)");
47 gc_ref
48 }
49 Err((error, _)) => {
50 println!(" ✗ First object allocation failed: {:?}", error);
51 return Ok(());
52 }
53 };
54
55 // Allocate second large object (1KB + header) - should exceed 2KB limit
56 println!("3. Try to allocate second large object...");
57 match unsafe { context.alloc_raw(partition_id, LargeData { data: [0; 1024] }) } {
58 Err((GcError::PartitionFull, _)) => {
59 println!(" ✓ Correctly detected partition full error");
60 }
61 Ok(_) => {
62 println!(" ✗ Expected partition full error, but allocation succeeded");
63 return Ok(());
64 }
65 Err((other_error, _)) => {
66 println!(
67 " ✗ Expected partition full error, but got: {:?}",
68 other_error
69 );
70 return Ok(());
71 }
72 }
73
74 // Clean up - through garbage collection instead of manual release
75 println!(" ✓ Automatic cleanup through GC");
76 context.garbage_collect(partition_id, GcHeap::DUMMY_DISPOSE_CALLBACK);
77
78 Ok(())
79}
80
81/// Demonstrate partition management errors
82fn demonstrate_partition_management_errors() -> GcResult<()> {
83 println!("1. Test non-existent partition operations...");
84
85 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
86 let invalid_partition = gc_lite::GcPartitionId(9999); // Non-existent partition
87
88 // Test allocating objects in non-existent partition
89 match unsafe {
90 context.alloc_raw(
91 invalid_partition,
92 TestData {
93 value: 42,
94 name: "test".to_string(),
95 },
96 )
97 } {
98 Err((GcError::PartitionNotFound, _)) => {
99 println!(" ✓ Allocating objects in non-existent partition returns correct error");
100 }
101 Ok(_) => {
102 println!(" ✗ Expected partition not found error, but allocation succeeded");
103 }
104 Err((other_error, _)) => {
105 println!(
106 " ✗ Expected partition not found error, but got: {:?}",
107 other_error
108 );
109 }
110 }
111
112 // Test getting non-existent partition information
113 let partition_info = context.partition(invalid_partition);
114 assert!(
115 partition_info.is_none(),
116 "Non-existent partition should return None"
117 );
118 println!(" ✓ Getting non-existent partition info returns None");
119
120 // Test removing non-existent partition (remove_partition doesn't return error, just silently fails)
121 context.remove_partition(invalid_partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
122 println!(" ✓ Removing non-existent partition silently fails");
123
124 println!("\n2. Test non-empty partition deletion...");
125 let partition_id = context.create_partition(64 * 1024, 16 * 1024);
126
127 // Allocate objects in partition
128 let obj = unsafe {
129 context.alloc_raw(
130 partition_id,
131 TestData {
132 value: 1,
133 name: "obj".to_string(),
134 },
135 )
136 }
137 .unwrap();
138 let _ = obj;
139
140 // Try to delete non-empty partition (remove_partition will force cleanup)
141 context.remove_partition(partition_id, GcHeap::DUMMY_DISPOSE_CALLBACK);
142 println!(" ✓ Successfully deleted non-empty partition (root objects were force cleaned)");
143
144 Ok(())
145}
146
147/// Demonstrate GC threshold API errors
148fn demonstrate_gc_threshold_errors() -> GcResult<()> {
149 println!("1. Test GC threshold API...");
150
151 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
152 context.set_memory_limit(1024);
153 let _partition_id = context.create_partition(64 * 1024, 16 * 1024);
154
155 // Test default values
156 println!("2. Test default threshold...");
157 assert_eq!(context.gc_threshold(), 0);
158 println!(" ✓ Default threshold is 0, automatic GC disabled");
159
160 // Test setting threshold
161 println!("3. Test setting threshold...");
162 context.set_gc_threshold(512);
163 assert_eq!(context.gc_threshold(), 512);
164 println!(" ✓ Successfully set threshold to 512, automatic GC enabled");
165
166 // Test setting threshold exceeding memory limit
167 println!("4. Test setting threshold exceeding memory limit...");
168 context.set_gc_threshold(2048);
169 // Since threshold exceeds memory limit, will be capped at 0.8x of limit (1024 * 8 / 10 = 819)
170 assert_eq!(context.gc_threshold(), 819);
171 println!(
172 " ✓ Setting threshold exceeding memory limit automatically adjusted to 0.8x of memory limit"
173 );
174
175 // Test disabling automatic GC
176 println!("5. Test disabling automatic GC...");
177 context.set_gc_threshold(0);
178 assert_eq!(context.gc_threshold(), 0);
179 println!(" ✓ Successfully disabled automatic GC, threshold set to 0");
180
181 Ok(())
182}47fn main() -> GcResult<()> {
48 println!("=== Basic usage example of partitioned garbage collection system ===");
49
50 // Create garbage collection context
51 let mut heap = GcHeap::new(&GC_TYPE_REGISTRY);
52
53 println!("Initial state:");
54 println!(" Number of partitions: {}", heap.partition_ids().len());
55
56 // Create two partitions
57 println!("\nCreate partitions:");
58 let partition1 = heap.create_partition(64 * 1024, 16 * 1024);
59 let partition2 = heap.create_partition(64 * 1024, 16 * 1024);
60 println!(" Created partition1: {:?}", partition1);
61 println!(" Created partition2: {:?}", partition2);
62 println!(" Number of partitions: {}", heap.partition_ids().len());
63
64 // Allocate objects in partition1
65 println!("\nAllocate objects in partition1:");
66 let obj1 = unsafe { heap.alloc_raw(partition1, MyString(String::from("Hello"))) }
67 .map_err(|(err, _)| err)?;
68 let obj2 = unsafe { heap.alloc_raw(partition1, MyI32(42)) }.map_err(|(err, _)| err)?;
69 let obj3 = unsafe { heap.alloc_raw(partition1, MyString(String::from("VectorData"))) }
70 .map_err(|(err, _)| err)?;
71
72 println!(" Created string: '{}'", unsafe { obj1.as_ref() });
73 println!(" Created number: {}", unsafe { obj2.as_ref() });
74 println!(" Created string: '{}'", unsafe { obj3.as_ref() });
75
76 // Allocate objects in partition2
77 println!("\nAllocate objects in partition2:");
78 let obj4 = unsafe { heap.alloc_raw(partition2, MyString(String::from("World"))) }
79 .map_err(|(err, _)| err)?;
80 let obj5 = unsafe { heap.alloc_raw(partition2, MyI32(99)) }.map_err(|(err, _)| err)?;
81
82 println!(" Created string: '{}'", unsafe { obj4.as_ref() });
83 println!(" Created number: {}", unsafe { obj5.as_ref() });
84
85 // Display partition status
86 println!("\nPartition status:");
87 for partition_id in heap.partition_ids() {
88 if let Some(partition) = heap.partition(partition_id) {
89 let limit = heap.memory_limit();
90 let usage = if limit > 0 {
91 format!(
92 "{}/{} bytes ({:.1}%)",
93 partition.memory_used(),
94 limit,
95 (partition.memory_used() as f64 / limit as f64) * 100.0
96 )
97 } else {
98 format!("{}/∞ bytes", partition.memory_used())
99 };
100 println!(
101 " {:?}: {} [自动GC: {}]",
102 partition_id,
103 usage,
104 if heap.gc_threshold() > 0 {
105 "Enabled"
106 } else {
107 "Disabled"
108 }
109 );
110 }
111 }
112
113 // Root objects are now implicitly managed by stack variables (e.g., obj1, obj2).
114 // No explicit `set_root` calls are needed for them.
115 println!("\nRoot objects are held by variables:");
116 println!(" Roots: obj1, obj2, obj3, obj4, obj5");
117
118 // Manually trigger garbage collection for partition1
119 println!("\nManually trigger garbage collection for partition1...");
120 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
121 println!(" Collected {} bytes", freed);
122
123 // Verify root objects are still valid
124 println!("\nVerify partition1 root objects are still valid:");
125 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
126 println!(" Object2: {}", unsafe { obj2.as_ref() });
127
128 // Manually trigger garbage collection for partition2
129 println!("\nManually trigger garbage collection for partition2...");
130 let freed = heap.garbage_collect(partition2, GcHeap::DUMMY_DISPOSE_CALLBACK);
131 println!(" Collected {} bytes", freed);
132
133 // Verify partition2 root objects are still valid
134 println!("\nVerify partition2 root objects are still valid:");
135 println!(" Object4: '{}'", unsafe { obj4.as_ref() });
136
137 // Trigger garbage collection for partition1 again to collect unreferenced objects
138 println!("\nTrigger garbage collection for partition1 again...");
139 // obj2 is no longer explicitly un-rooted, but we can simulate it going out of scope
140 // to test collection. For this example, we'll just collect other garbage.
141 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
142 println!(" Collected {} bytes", freed);
143
144 // Verify remaining root objects are still valid
145 println!("\nVerify remaining root objects are still valid:");
146 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
147 println!(" Object2: {} (still a root)", unsafe { obj2.as_ref() });
148
149 // Demonstrate automatic garbage collection
150 println!("\nDemonstrate automatic garbage collection...");
151
152 // Create a small partition to demonstrate automatic GC
153 let small_partition = heap.create_partition(64 * 1024, 16 * 1024);
154
155 // Allocate multiple objects to fill partition
156 for i in 0..5 {
157 let _obj = unsafe { heap.alloc_raw(small_partition, MyString(format!("Object {}", i))) }
158 .map_err(|(err, _)| err)?;
159 }
160
161 println!(" Allocated 5 objects in small partition");
162
163 // Demonstrate weak references
164 println!("\nDemonstrate weak references:");
165 let weak_ref = heap.downgrade(&obj1);
166 println!(" Created weak reference: {:?}", weak_ref);
167
168 // Upgrade weak reference
169 match weak_ref.upgrade(&heap) {
170 Some(strong_ref) => {
171 println!(" Weak reference upgrade successful: '{}'", &*strong_ref);
172 }
173 None => {
174 println!(" Weak reference upgrade failed");
175 }
176 }
177
178 // Demonstrate complex types with GC references
179 println!("\nDemonstrate complex types with GC references:");
180 let mut node1 =
181 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 1")) }.map_err(|(err, _)| err)?;
182 let mut node2 =
183 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 2")) }.map_err(|(err, _)| err)?;
184
185 // Establish references between nodes
186 {
187 unsafe {
188 node1.with_write_barrier(&mut heap, |n| n.add_child(node2));
189 }
190 unsafe {
191 node2.with_write_barrier(&mut heap, |n| n.add_child(node1));
192 }
193 }
194
195 println!(" Created node1: {}", unsafe { node1.as_ref() });
196 println!(" Created node2: {}", unsafe { node2.as_ref() });
197
198 // Trigger garbage collection, verify circular references are handled correctly
199 println!("\nGarbage collection for handling circular references...");
200 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
201 println!(" 回收了 {} 字节内存", freed);
202
203 // Demonstrate partition deletion
204 println!("\nDemonstrate partition deletion:");
205
206 // Create an empty partition
207 let empty_partition = heap.create_partition(64 * 1024, 16 * 1024);
208 println!(" Created empty partition: {:?}", empty_partition);
209
210 // Delete empty partition
211 heap.remove_partition(empty_partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
212 println!(" Deleted empty partition successfully");
213
214 // Delete non-empty partition
215 heap.remove_partition(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
216 println!(" Deleted non-empty partition successfully");
217
218 println!("\nExample completed!");
219 Ok(())
220}Sourcepub fn finalize_partition(
&self,
partition_id: GcPartitionId,
) -> Option<GcNodeLink>
pub fn finalize_partition( &self, partition_id: GcPartitionId, ) -> Option<GcNodeLink>
Phase 1: Finalize — call Drop on all node payloads without freeing memory.
Only takes &self, so Drop implementations can safely access GcHeap
via a shared reference. Returns the node link containing all finalized
nodes, which must be passed to [dealloc_partition] to reclaim memory.
Scope caches associated with this partition are cleared before any drops
are called, so that GcScopeState::clear() (which only touches node flags)
runs before payload drops.
Sourcepub fn dealloc_partition(
&mut self,
partition_id: GcPartitionId,
link: GcNodeLink,
) -> usize
pub fn dealloc_partition( &mut self, partition_id: GcPartitionId, link: GcNodeLink, ) -> usize
Phase 2: Dealloc — free memory of all finalized nodes and reset the partition.
Takes &mut self — no Drop callbacks run at this point, so there is
no risk of reentrant &mut self access. The link must be the value
returned by [finalize_partition] for the same partition.
Returns the total number of bytes freed.
Sourcepub fn remove_partition(
&mut self,
partition_id: GcPartitionId,
_on_dispose: impl Fn(&GcHeap, &GcHead),
) -> usize
👎Deprecated: unsound — use finalize_partition(&self) + dealloc_partition(&mut self) instead
pub fn remove_partition( &mut self, partition_id: GcPartitionId, _on_dispose: impl Fn(&GcHeap, &GcHead), ) -> usize
unsound — use finalize_partition(&self) + dealloc_partition(&mut self) instead
Remove a partition and reclaim all its memory.
⚠️ DEPRECATED — This method is inherently unsound. It holds &mut self
while Drop callbacks run inside [finalize_partition], and those
callbacks can re-enter GcHeap through raw pointers, creating aliasing
&mut references (UB).
Use the two-phase API instead:
let link = gc_heap.finalize_partition(pid);
// ... (Drop callbacks that access GcHeap are safe here) ...
if let Some(link) = link {
gc_heap.dealloc_partition(pid, link);
}See [finalize_partition] (takes &self) and [dealloc_partition]
(takes &mut self) for details.
The on_dispose parameter is kept for API compatibility but is no
longer called — Drop is handled internally by finalize_partition.
Examples found in repository?
82fn demonstrate_partition_management_errors() -> GcResult<()> {
83 println!("1. Test non-existent partition operations...");
84
85 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
86 let invalid_partition = gc_lite::GcPartitionId(9999); // Non-existent partition
87
88 // Test allocating objects in non-existent partition
89 match unsafe {
90 context.alloc_raw(
91 invalid_partition,
92 TestData {
93 value: 42,
94 name: "test".to_string(),
95 },
96 )
97 } {
98 Err((GcError::PartitionNotFound, _)) => {
99 println!(" ✓ Allocating objects in non-existent partition returns correct error");
100 }
101 Ok(_) => {
102 println!(" ✗ Expected partition not found error, but allocation succeeded");
103 }
104 Err((other_error, _)) => {
105 println!(
106 " ✗ Expected partition not found error, but got: {:?}",
107 other_error
108 );
109 }
110 }
111
112 // Test getting non-existent partition information
113 let partition_info = context.partition(invalid_partition);
114 assert!(
115 partition_info.is_none(),
116 "Non-existent partition should return None"
117 );
118 println!(" ✓ Getting non-existent partition info returns None");
119
120 // Test removing non-existent partition (remove_partition doesn't return error, just silently fails)
121 context.remove_partition(invalid_partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
122 println!(" ✓ Removing non-existent partition silently fails");
123
124 println!("\n2. Test non-empty partition deletion...");
125 let partition_id = context.create_partition(64 * 1024, 16 * 1024);
126
127 // Allocate objects in partition
128 let obj = unsafe {
129 context.alloc_raw(
130 partition_id,
131 TestData {
132 value: 1,
133 name: "obj".to_string(),
134 },
135 )
136 }
137 .unwrap();
138 let _ = obj;
139
140 // Try to delete non-empty partition (remove_partition will force cleanup)
141 context.remove_partition(partition_id, GcHeap::DUMMY_DISPOSE_CALLBACK);
142 println!(" ✓ Successfully deleted non-empty partition (root objects were force cleaned)");
143
144 Ok(())
145}More examples
47fn main() -> GcResult<()> {
48 println!("=== Basic usage example of partitioned garbage collection system ===");
49
50 // Create garbage collection context
51 let mut heap = GcHeap::new(&GC_TYPE_REGISTRY);
52
53 println!("Initial state:");
54 println!(" Number of partitions: {}", heap.partition_ids().len());
55
56 // Create two partitions
57 println!("\nCreate partitions:");
58 let partition1 = heap.create_partition(64 * 1024, 16 * 1024);
59 let partition2 = heap.create_partition(64 * 1024, 16 * 1024);
60 println!(" Created partition1: {:?}", partition1);
61 println!(" Created partition2: {:?}", partition2);
62 println!(" Number of partitions: {}", heap.partition_ids().len());
63
64 // Allocate objects in partition1
65 println!("\nAllocate objects in partition1:");
66 let obj1 = unsafe { heap.alloc_raw(partition1, MyString(String::from("Hello"))) }
67 .map_err(|(err, _)| err)?;
68 let obj2 = unsafe { heap.alloc_raw(partition1, MyI32(42)) }.map_err(|(err, _)| err)?;
69 let obj3 = unsafe { heap.alloc_raw(partition1, MyString(String::from("VectorData"))) }
70 .map_err(|(err, _)| err)?;
71
72 println!(" Created string: '{}'", unsafe { obj1.as_ref() });
73 println!(" Created number: {}", unsafe { obj2.as_ref() });
74 println!(" Created string: '{}'", unsafe { obj3.as_ref() });
75
76 // Allocate objects in partition2
77 println!("\nAllocate objects in partition2:");
78 let obj4 = unsafe { heap.alloc_raw(partition2, MyString(String::from("World"))) }
79 .map_err(|(err, _)| err)?;
80 let obj5 = unsafe { heap.alloc_raw(partition2, MyI32(99)) }.map_err(|(err, _)| err)?;
81
82 println!(" Created string: '{}'", unsafe { obj4.as_ref() });
83 println!(" Created number: {}", unsafe { obj5.as_ref() });
84
85 // Display partition status
86 println!("\nPartition status:");
87 for partition_id in heap.partition_ids() {
88 if let Some(partition) = heap.partition(partition_id) {
89 let limit = heap.memory_limit();
90 let usage = if limit > 0 {
91 format!(
92 "{}/{} bytes ({:.1}%)",
93 partition.memory_used(),
94 limit,
95 (partition.memory_used() as f64 / limit as f64) * 100.0
96 )
97 } else {
98 format!("{}/∞ bytes", partition.memory_used())
99 };
100 println!(
101 " {:?}: {} [自动GC: {}]",
102 partition_id,
103 usage,
104 if heap.gc_threshold() > 0 {
105 "Enabled"
106 } else {
107 "Disabled"
108 }
109 );
110 }
111 }
112
113 // Root objects are now implicitly managed by stack variables (e.g., obj1, obj2).
114 // No explicit `set_root` calls are needed for them.
115 println!("\nRoot objects are held by variables:");
116 println!(" Roots: obj1, obj2, obj3, obj4, obj5");
117
118 // Manually trigger garbage collection for partition1
119 println!("\nManually trigger garbage collection for partition1...");
120 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
121 println!(" Collected {} bytes", freed);
122
123 // Verify root objects are still valid
124 println!("\nVerify partition1 root objects are still valid:");
125 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
126 println!(" Object2: {}", unsafe { obj2.as_ref() });
127
128 // Manually trigger garbage collection for partition2
129 println!("\nManually trigger garbage collection for partition2...");
130 let freed = heap.garbage_collect(partition2, GcHeap::DUMMY_DISPOSE_CALLBACK);
131 println!(" Collected {} bytes", freed);
132
133 // Verify partition2 root objects are still valid
134 println!("\nVerify partition2 root objects are still valid:");
135 println!(" Object4: '{}'", unsafe { obj4.as_ref() });
136
137 // Trigger garbage collection for partition1 again to collect unreferenced objects
138 println!("\nTrigger garbage collection for partition1 again...");
139 // obj2 is no longer explicitly un-rooted, but we can simulate it going out of scope
140 // to test collection. For this example, we'll just collect other garbage.
141 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
142 println!(" Collected {} bytes", freed);
143
144 // Verify remaining root objects are still valid
145 println!("\nVerify remaining root objects are still valid:");
146 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
147 println!(" Object2: {} (still a root)", unsafe { obj2.as_ref() });
148
149 // Demonstrate automatic garbage collection
150 println!("\nDemonstrate automatic garbage collection...");
151
152 // Create a small partition to demonstrate automatic GC
153 let small_partition = heap.create_partition(64 * 1024, 16 * 1024);
154
155 // Allocate multiple objects to fill partition
156 for i in 0..5 {
157 let _obj = unsafe { heap.alloc_raw(small_partition, MyString(format!("Object {}", i))) }
158 .map_err(|(err, _)| err)?;
159 }
160
161 println!(" Allocated 5 objects in small partition");
162
163 // Demonstrate weak references
164 println!("\nDemonstrate weak references:");
165 let weak_ref = heap.downgrade(&obj1);
166 println!(" Created weak reference: {:?}", weak_ref);
167
168 // Upgrade weak reference
169 match weak_ref.upgrade(&heap) {
170 Some(strong_ref) => {
171 println!(" Weak reference upgrade successful: '{}'", &*strong_ref);
172 }
173 None => {
174 println!(" Weak reference upgrade failed");
175 }
176 }
177
178 // Demonstrate complex types with GC references
179 println!("\nDemonstrate complex types with GC references:");
180 let mut node1 =
181 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 1")) }.map_err(|(err, _)| err)?;
182 let mut node2 =
183 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 2")) }.map_err(|(err, _)| err)?;
184
185 // Establish references between nodes
186 {
187 unsafe {
188 node1.with_write_barrier(&mut heap, |n| n.add_child(node2));
189 }
190 unsafe {
191 node2.with_write_barrier(&mut heap, |n| n.add_child(node1));
192 }
193 }
194
195 println!(" Created node1: {}", unsafe { node1.as_ref() });
196 println!(" Created node2: {}", unsafe { node2.as_ref() });
197
198 // Trigger garbage collection, verify circular references are handled correctly
199 println!("\nGarbage collection for handling circular references...");
200 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
201 println!(" 回收了 {} 字节内存", freed);
202
203 // Demonstrate partition deletion
204 println!("\nDemonstrate partition deletion:");
205
206 // Create an empty partition
207 let empty_partition = heap.create_partition(64 * 1024, 16 * 1024);
208 println!(" Created empty partition: {:?}", empty_partition);
209
210 // Delete empty partition
211 heap.remove_partition(empty_partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
212 println!(" Deleted empty partition successfully");
213
214 // Delete non-empty partition
215 heap.remove_partition(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
216 println!(" Deleted non-empty partition successfully");
217
218 println!("\nExample completed!");
219 Ok(())
220}Sourcepub fn partition(&self, partition_id: GcPartitionId) -> Option<&GcPartition>
pub fn partition(&self, partition_id: GcPartitionId) -> Option<&GcPartition>
Get partition information
Examples found in repository?
156fn benchmark_memory_efficiency() {
157 println!("\nTesting memory usage efficiency...");
158
159 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
160 context.set_memory_limit(1024 * 1024); // 1MB global limit
161 let partition = context.create_partition(64 * 1024, 16 * 1024);
162
163 // Allocate many small objects
164 let small_objects_count = 1000;
165 let mut small_objects = Vec::new();
166
167 for _i in 0..small_objects_count {
168 let obj = unsafe { context.alloc_raw(partition, SmallData {}) }.unwrap();
169 small_objects.push(obj);
170 }
171
172 if let Some(partition_info) = context.partition(partition) {
173 let used = partition_info.memory_used();
174 let limit = context.memory_limit();
175 let efficiency = if limit > 0 {
176 (used as f64 / limit as f64) * 100.0
177 } else {
178 0.0
179 };
180
181 println!(" After allocating {} small objects:", small_objects_count);
182 println!(
183 " Memory usage: {}/{} bytes ({:.1}%)",
184 used, limit, efficiency
185 );
186 println!(
187 " Average overhead per object: {} bytes",
188 if small_objects_count > 0 {
189 used / small_objects_count
190 } else {
191 0
192 }
193 );
194 }
195
196 // Collect all objects
197 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
198 println!(" Collected all objects, freed {} bytes", freed);
199
200 // Verify complete memory collection
201 if let Some(partition_info) = context.partition(partition) {
202 let used_after = partition_info.memory_used();
203 println!(" Memory usage after collection: {} bytes", used_after);
204 println!(
205 " Memory collection rate: {:.1}%",
206 if freed > 0 {
207 (freed as f64 / (freed + used_after) as f64) * 100.0
208 } else {
209 0.0
210 }
211 );
212 }
213}
214
215/// Test automatic GC threshold performance
216fn benchmark_auto_gc_threshold() {
217 println!("\nTesting automatic GC threshold performance...");
218
219 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
220 context.set_memory_limit(2048); // 2KB global limit
221 let partition = context.create_partition(64 * 1024, 16 * 1024);
222
223 // Set automatic GC threshold to 1.5KB
224 context.set_gc_threshold(1500);
225
226 // Allocate objects until automatic GC is triggered
227 let mut allocated_bytes = 0;
228 let mut object_count = 0;
229
230 println!(" Allocating objects until automatic GC is triggered...");
231
232 for _i in 0..100 {
233 // Try at most 100 times
234 // Allocate objects of about 100 bytes
235 let node = SimpleNode {
236 _data: vec![0u8; 100],
237 };
238 match unsafe { context.alloc_raw(partition, node) } {
239 Ok(_gc_ref) => {
240 allocated_bytes += 100 + std::mem::size_of::<GcRef<SimpleNode>>(); // Estimated size
241 object_count += 1;
242
243 // Check if approaching threshold
244 if let Some(partition_info) = context.partition(partition)
245 && partition_info.memory_used() >= 1500
246 {
247 println!(
248 " Reached automatic GC threshold, allocated {} objects",
249 object_count
250 );
251 println!(" Estimated allocated memory: {} bytes", allocated_bytes);
252 println!(
253 " Actual memory usage: {} bytes",
254 partition_info.memory_used()
255 );
256 break;
257 }
258 }
259 Err(_) => {
260 println!(" Allocation failed, automatic GC may have been triggered");
261 break;
262 }
263 }
264 }
265
266 // Manually trigger GC to see effect
267 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
268 println!(" Manual GC freed {} bytes", freed);
269}More examples
82fn demonstrate_partition_management_errors() -> GcResult<()> {
83 println!("1. Test non-existent partition operations...");
84
85 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
86 let invalid_partition = gc_lite::GcPartitionId(9999); // Non-existent partition
87
88 // Test allocating objects in non-existent partition
89 match unsafe {
90 context.alloc_raw(
91 invalid_partition,
92 TestData {
93 value: 42,
94 name: "test".to_string(),
95 },
96 )
97 } {
98 Err((GcError::PartitionNotFound, _)) => {
99 println!(" ✓ Allocating objects in non-existent partition returns correct error");
100 }
101 Ok(_) => {
102 println!(" ✗ Expected partition not found error, but allocation succeeded");
103 }
104 Err((other_error, _)) => {
105 println!(
106 " ✗ Expected partition not found error, but got: {:?}",
107 other_error
108 );
109 }
110 }
111
112 // Test getting non-existent partition information
113 let partition_info = context.partition(invalid_partition);
114 assert!(
115 partition_info.is_none(),
116 "Non-existent partition should return None"
117 );
118 println!(" ✓ Getting non-existent partition info returns None");
119
120 // Test removing non-existent partition (remove_partition doesn't return error, just silently fails)
121 context.remove_partition(invalid_partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
122 println!(" ✓ Removing non-existent partition silently fails");
123
124 println!("\n2. Test non-empty partition deletion...");
125 let partition_id = context.create_partition(64 * 1024, 16 * 1024);
126
127 // Allocate objects in partition
128 let obj = unsafe {
129 context.alloc_raw(
130 partition_id,
131 TestData {
132 value: 1,
133 name: "obj".to_string(),
134 },
135 )
136 }
137 .unwrap();
138 let _ = obj;
139
140 // Try to delete non-empty partition (remove_partition will force cleanup)
141 context.remove_partition(partition_id, GcHeap::DUMMY_DISPOSE_CALLBACK);
142 println!(" ✓ Successfully deleted non-empty partition (root objects were force cleaned)");
143
144 Ok(())
145}47fn main() -> GcResult<()> {
48 println!("=== Basic usage example of partitioned garbage collection system ===");
49
50 // Create garbage collection context
51 let mut heap = GcHeap::new(&GC_TYPE_REGISTRY);
52
53 println!("Initial state:");
54 println!(" Number of partitions: {}", heap.partition_ids().len());
55
56 // Create two partitions
57 println!("\nCreate partitions:");
58 let partition1 = heap.create_partition(64 * 1024, 16 * 1024);
59 let partition2 = heap.create_partition(64 * 1024, 16 * 1024);
60 println!(" Created partition1: {:?}", partition1);
61 println!(" Created partition2: {:?}", partition2);
62 println!(" Number of partitions: {}", heap.partition_ids().len());
63
64 // Allocate objects in partition1
65 println!("\nAllocate objects in partition1:");
66 let obj1 = unsafe { heap.alloc_raw(partition1, MyString(String::from("Hello"))) }
67 .map_err(|(err, _)| err)?;
68 let obj2 = unsafe { heap.alloc_raw(partition1, MyI32(42)) }.map_err(|(err, _)| err)?;
69 let obj3 = unsafe { heap.alloc_raw(partition1, MyString(String::from("VectorData"))) }
70 .map_err(|(err, _)| err)?;
71
72 println!(" Created string: '{}'", unsafe { obj1.as_ref() });
73 println!(" Created number: {}", unsafe { obj2.as_ref() });
74 println!(" Created string: '{}'", unsafe { obj3.as_ref() });
75
76 // Allocate objects in partition2
77 println!("\nAllocate objects in partition2:");
78 let obj4 = unsafe { heap.alloc_raw(partition2, MyString(String::from("World"))) }
79 .map_err(|(err, _)| err)?;
80 let obj5 = unsafe { heap.alloc_raw(partition2, MyI32(99)) }.map_err(|(err, _)| err)?;
81
82 println!(" Created string: '{}'", unsafe { obj4.as_ref() });
83 println!(" Created number: {}", unsafe { obj5.as_ref() });
84
85 // Display partition status
86 println!("\nPartition status:");
87 for partition_id in heap.partition_ids() {
88 if let Some(partition) = heap.partition(partition_id) {
89 let limit = heap.memory_limit();
90 let usage = if limit > 0 {
91 format!(
92 "{}/{} bytes ({:.1}%)",
93 partition.memory_used(),
94 limit,
95 (partition.memory_used() as f64 / limit as f64) * 100.0
96 )
97 } else {
98 format!("{}/∞ bytes", partition.memory_used())
99 };
100 println!(
101 " {:?}: {} [自动GC: {}]",
102 partition_id,
103 usage,
104 if heap.gc_threshold() > 0 {
105 "Enabled"
106 } else {
107 "Disabled"
108 }
109 );
110 }
111 }
112
113 // Root objects are now implicitly managed by stack variables (e.g., obj1, obj2).
114 // No explicit `set_root` calls are needed for them.
115 println!("\nRoot objects are held by variables:");
116 println!(" Roots: obj1, obj2, obj3, obj4, obj5");
117
118 // Manually trigger garbage collection for partition1
119 println!("\nManually trigger garbage collection for partition1...");
120 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
121 println!(" Collected {} bytes", freed);
122
123 // Verify root objects are still valid
124 println!("\nVerify partition1 root objects are still valid:");
125 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
126 println!(" Object2: {}", unsafe { obj2.as_ref() });
127
128 // Manually trigger garbage collection for partition2
129 println!("\nManually trigger garbage collection for partition2...");
130 let freed = heap.garbage_collect(partition2, GcHeap::DUMMY_DISPOSE_CALLBACK);
131 println!(" Collected {} bytes", freed);
132
133 // Verify partition2 root objects are still valid
134 println!("\nVerify partition2 root objects are still valid:");
135 println!(" Object4: '{}'", unsafe { obj4.as_ref() });
136
137 // Trigger garbage collection for partition1 again to collect unreferenced objects
138 println!("\nTrigger garbage collection for partition1 again...");
139 // obj2 is no longer explicitly un-rooted, but we can simulate it going out of scope
140 // to test collection. For this example, we'll just collect other garbage.
141 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
142 println!(" Collected {} bytes", freed);
143
144 // Verify remaining root objects are still valid
145 println!("\nVerify remaining root objects are still valid:");
146 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
147 println!(" Object2: {} (still a root)", unsafe { obj2.as_ref() });
148
149 // Demonstrate automatic garbage collection
150 println!("\nDemonstrate automatic garbage collection...");
151
152 // Create a small partition to demonstrate automatic GC
153 let small_partition = heap.create_partition(64 * 1024, 16 * 1024);
154
155 // Allocate multiple objects to fill partition
156 for i in 0..5 {
157 let _obj = unsafe { heap.alloc_raw(small_partition, MyString(format!("Object {}", i))) }
158 .map_err(|(err, _)| err)?;
159 }
160
161 println!(" Allocated 5 objects in small partition");
162
163 // Demonstrate weak references
164 println!("\nDemonstrate weak references:");
165 let weak_ref = heap.downgrade(&obj1);
166 println!(" Created weak reference: {:?}", weak_ref);
167
168 // Upgrade weak reference
169 match weak_ref.upgrade(&heap) {
170 Some(strong_ref) => {
171 println!(" Weak reference upgrade successful: '{}'", &*strong_ref);
172 }
173 None => {
174 println!(" Weak reference upgrade failed");
175 }
176 }
177
178 // Demonstrate complex types with GC references
179 println!("\nDemonstrate complex types with GC references:");
180 let mut node1 =
181 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 1")) }.map_err(|(err, _)| err)?;
182 let mut node2 =
183 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 2")) }.map_err(|(err, _)| err)?;
184
185 // Establish references between nodes
186 {
187 unsafe {
188 node1.with_write_barrier(&mut heap, |n| n.add_child(node2));
189 }
190 unsafe {
191 node2.with_write_barrier(&mut heap, |n| n.add_child(node1));
192 }
193 }
194
195 println!(" Created node1: {}", unsafe { node1.as_ref() });
196 println!(" Created node2: {}", unsafe { node2.as_ref() });
197
198 // Trigger garbage collection, verify circular references are handled correctly
199 println!("\nGarbage collection for handling circular references...");
200 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
201 println!(" 回收了 {} 字节内存", freed);
202
203 // Demonstrate partition deletion
204 println!("\nDemonstrate partition deletion:");
205
206 // Create an empty partition
207 let empty_partition = heap.create_partition(64 * 1024, 16 * 1024);
208 println!(" Created empty partition: {:?}", empty_partition);
209
210 // Delete empty partition
211 heap.remove_partition(empty_partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
212 println!(" Deleted empty partition successfully");
213
214 // Delete non-empty partition
215 heap.remove_partition(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
216 println!(" Deleted non-empty partition successfully");
217
218 println!("\nExample completed!");
219 Ok(())
220}Sourcepub fn partition_mut(
&mut self,
partition_id: GcPartitionId,
) -> Option<&mut GcPartition>
pub fn partition_mut( &mut self, partition_id: GcPartitionId, ) -> Option<&mut GcPartition>
Get partition information
Sourcepub fn partition_ids(&self) -> Vec<GcPartitionId>
pub fn partition_ids(&self) -> Vec<GcPartitionId>
Get all partition IDs
Examples found in repository?
47fn main() -> GcResult<()> {
48 println!("=== Basic usage example of partitioned garbage collection system ===");
49
50 // Create garbage collection context
51 let mut heap = GcHeap::new(&GC_TYPE_REGISTRY);
52
53 println!("Initial state:");
54 println!(" Number of partitions: {}", heap.partition_ids().len());
55
56 // Create two partitions
57 println!("\nCreate partitions:");
58 let partition1 = heap.create_partition(64 * 1024, 16 * 1024);
59 let partition2 = heap.create_partition(64 * 1024, 16 * 1024);
60 println!(" Created partition1: {:?}", partition1);
61 println!(" Created partition2: {:?}", partition2);
62 println!(" Number of partitions: {}", heap.partition_ids().len());
63
64 // Allocate objects in partition1
65 println!("\nAllocate objects in partition1:");
66 let obj1 = unsafe { heap.alloc_raw(partition1, MyString(String::from("Hello"))) }
67 .map_err(|(err, _)| err)?;
68 let obj2 = unsafe { heap.alloc_raw(partition1, MyI32(42)) }.map_err(|(err, _)| err)?;
69 let obj3 = unsafe { heap.alloc_raw(partition1, MyString(String::from("VectorData"))) }
70 .map_err(|(err, _)| err)?;
71
72 println!(" Created string: '{}'", unsafe { obj1.as_ref() });
73 println!(" Created number: {}", unsafe { obj2.as_ref() });
74 println!(" Created string: '{}'", unsafe { obj3.as_ref() });
75
76 // Allocate objects in partition2
77 println!("\nAllocate objects in partition2:");
78 let obj4 = unsafe { heap.alloc_raw(partition2, MyString(String::from("World"))) }
79 .map_err(|(err, _)| err)?;
80 let obj5 = unsafe { heap.alloc_raw(partition2, MyI32(99)) }.map_err(|(err, _)| err)?;
81
82 println!(" Created string: '{}'", unsafe { obj4.as_ref() });
83 println!(" Created number: {}", unsafe { obj5.as_ref() });
84
85 // Display partition status
86 println!("\nPartition status:");
87 for partition_id in heap.partition_ids() {
88 if let Some(partition) = heap.partition(partition_id) {
89 let limit = heap.memory_limit();
90 let usage = if limit > 0 {
91 format!(
92 "{}/{} bytes ({:.1}%)",
93 partition.memory_used(),
94 limit,
95 (partition.memory_used() as f64 / limit as f64) * 100.0
96 )
97 } else {
98 format!("{}/∞ bytes", partition.memory_used())
99 };
100 println!(
101 " {:?}: {} [自动GC: {}]",
102 partition_id,
103 usage,
104 if heap.gc_threshold() > 0 {
105 "Enabled"
106 } else {
107 "Disabled"
108 }
109 );
110 }
111 }
112
113 // Root objects are now implicitly managed by stack variables (e.g., obj1, obj2).
114 // No explicit `set_root` calls are needed for them.
115 println!("\nRoot objects are held by variables:");
116 println!(" Roots: obj1, obj2, obj3, obj4, obj5");
117
118 // Manually trigger garbage collection for partition1
119 println!("\nManually trigger garbage collection for partition1...");
120 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
121 println!(" Collected {} bytes", freed);
122
123 // Verify root objects are still valid
124 println!("\nVerify partition1 root objects are still valid:");
125 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
126 println!(" Object2: {}", unsafe { obj2.as_ref() });
127
128 // Manually trigger garbage collection for partition2
129 println!("\nManually trigger garbage collection for partition2...");
130 let freed = heap.garbage_collect(partition2, GcHeap::DUMMY_DISPOSE_CALLBACK);
131 println!(" Collected {} bytes", freed);
132
133 // Verify partition2 root objects are still valid
134 println!("\nVerify partition2 root objects are still valid:");
135 println!(" Object4: '{}'", unsafe { obj4.as_ref() });
136
137 // Trigger garbage collection for partition1 again to collect unreferenced objects
138 println!("\nTrigger garbage collection for partition1 again...");
139 // obj2 is no longer explicitly un-rooted, but we can simulate it going out of scope
140 // to test collection. For this example, we'll just collect other garbage.
141 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
142 println!(" Collected {} bytes", freed);
143
144 // Verify remaining root objects are still valid
145 println!("\nVerify remaining root objects are still valid:");
146 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
147 println!(" Object2: {} (still a root)", unsafe { obj2.as_ref() });
148
149 // Demonstrate automatic garbage collection
150 println!("\nDemonstrate automatic garbage collection...");
151
152 // Create a small partition to demonstrate automatic GC
153 let small_partition = heap.create_partition(64 * 1024, 16 * 1024);
154
155 // Allocate multiple objects to fill partition
156 for i in 0..5 {
157 let _obj = unsafe { heap.alloc_raw(small_partition, MyString(format!("Object {}", i))) }
158 .map_err(|(err, _)| err)?;
159 }
160
161 println!(" Allocated 5 objects in small partition");
162
163 // Demonstrate weak references
164 println!("\nDemonstrate weak references:");
165 let weak_ref = heap.downgrade(&obj1);
166 println!(" Created weak reference: {:?}", weak_ref);
167
168 // Upgrade weak reference
169 match weak_ref.upgrade(&heap) {
170 Some(strong_ref) => {
171 println!(" Weak reference upgrade successful: '{}'", &*strong_ref);
172 }
173 None => {
174 println!(" Weak reference upgrade failed");
175 }
176 }
177
178 // Demonstrate complex types with GC references
179 println!("\nDemonstrate complex types with GC references:");
180 let mut node1 =
181 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 1")) }.map_err(|(err, _)| err)?;
182 let mut node2 =
183 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 2")) }.map_err(|(err, _)| err)?;
184
185 // Establish references between nodes
186 {
187 unsafe {
188 node1.with_write_barrier(&mut heap, |n| n.add_child(node2));
189 }
190 unsafe {
191 node2.with_write_barrier(&mut heap, |n| n.add_child(node1));
192 }
193 }
194
195 println!(" Created node1: {}", unsafe { node1.as_ref() });
196 println!(" Created node2: {}", unsafe { node2.as_ref() });
197
198 // Trigger garbage collection, verify circular references are handled correctly
199 println!("\nGarbage collection for handling circular references...");
200 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
201 println!(" 回收了 {} 字节内存", freed);
202
203 // Demonstrate partition deletion
204 println!("\nDemonstrate partition deletion:");
205
206 // Create an empty partition
207 let empty_partition = heap.create_partition(64 * 1024, 16 * 1024);
208 println!(" Created empty partition: {:?}", empty_partition);
209
210 // Delete empty partition
211 heap.remove_partition(empty_partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
212 println!(" Deleted empty partition successfully");
213
214 // Delete non-empty partition
215 heap.remove_partition(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
216 println!(" Deleted non-empty partition successfully");
217
218 println!("\nExample completed!");
219 Ok(())
220}Source§impl GcHeap
impl GcHeap
Sourcepub fn acquire_scope_stack(&mut self, par: GcPartitionId) -> GcScopeStackId
pub fn acquire_scope_stack(&mut self, par: GcPartitionId) -> GcScopeStackId
find an idle scope stack, or create a new if none available
Examples found in repository?
56fn main() -> GcResult<()> {
57 let mut heap = GcHeap::new(&GC_TYPE_REGISTRY);
58 let partition = heap.create_partition(64 * 1024, 16 * 1024);
59 let stack_id = heap.acquire_scope_stack(partition);
60
61 let static_ref = alloc_static(&mut heap, stack_id, 10)?;
62 let other_ref = alloc_other(&mut heap, stack_id, 20)?;
63
64 println!(
65 "Static node value: {}",
66 unsafe { static_ref.as_ref() }._value
67 );
68 println!("Other node value: {}", unsafe { other_ref.as_ref() }._value);
69
70 heap.release_scope_stack(stack_id);
71
72 println!("gc_node_usage example verified");
73
74 Ok(())
75}Sourcepub fn release_scope_stack(&mut self, stack_id: GcScopeStackId)
pub fn release_scope_stack(&mut self, stack_id: GcScopeStackId)
Examples found in repository?
56fn main() -> GcResult<()> {
57 let mut heap = GcHeap::new(&GC_TYPE_REGISTRY);
58 let partition = heap.create_partition(64 * 1024, 16 * 1024);
59 let stack_id = heap.acquire_scope_stack(partition);
60
61 let static_ref = alloc_static(&mut heap, stack_id, 10)?;
62 let other_ref = alloc_other(&mut heap, stack_id, 20)?;
63
64 println!(
65 "Static node value: {}",
66 unsafe { static_ref.as_ref() }._value
67 );
68 println!("Other node value: {}", unsafe { other_ref.as_ref() }._value);
69
70 heap.release_scope_stack(stack_id);
71
72 println!("gc_node_usage example verified");
73
74 Ok(())
75}Sourcepub fn scope_max_depth(&self, stack_id: GcScopeStackId) -> u32
pub fn scope_max_depth(&self, stack_id: GcScopeStackId) -> u32
get max depth of a scope stack
Sourcepub fn scope(
&self,
stack_id: GcScopeStackId,
depth: u32,
) -> Option<&GcScopeState<'_>>
pub fn scope( &self, stack_id: GcScopeStackId, depth: u32, ) -> Option<&GcScopeState<'_>>
get scope state specified by (stack_id, depth).
where depth is 1-based (1 means index #0)
Sourcepub unsafe fn scope_unchecked(
&self,
stack_id: GcScopeStackId,
index: u32,
) -> &GcScopeState<'_>
pub unsafe fn scope_unchecked( &self, stack_id: GcScopeStackId, index: u32, ) -> &GcScopeState<'_>
Get scope state by 0-based index without bounds check.
§Safety
Caller must ensure index < scope_max_depth(stack_id).
Sourcepub fn new_scope<'s>(&'s mut self, stack_id: GcScopeStackId) -> GcScope<'s>
pub fn new_scope<'s>(&'s mut self, stack_id: GcScopeStackId) -> GcScope<'s>
push a new scope on the stack, returns new scope’s handle. the scope will be automatically popped when this handle is dropped.
§Panics
Panics if an earlier handle is dropped while a later handle is still alive (LIFO order violation is enforced at runtime).
Sourcepub fn current_scope(
&self,
stack_id: GcScopeStackId,
) -> Option<&GcScopeState<'_>>
pub fn current_scope( &self, stack_id: GcScopeStackId, ) -> Option<&GcScopeState<'_>>
get last (top-most) scope from the stack
Sourcepub fn with_current_scope_of<R>(
&mut self,
stack_id: GcScopeStackId,
f: impl FnOnce(&mut GcScopeState<'_>) -> R,
) -> Option<R>
pub fn with_current_scope_of<R>( &mut self, stack_id: GcScopeStackId, f: impl FnOnce(&mut GcScopeState<'_>) -> R, ) -> Option<R>
run closure with last (top-most) scope from the stack
Sourcepub fn with_new_scope<R>(
&mut self,
stack_id: GcScopeStackId,
f: impl FnOnce(GcScope<'_>) -> R,
) -> R
pub fn with_new_scope<R>( &mut self, stack_id: GcScopeStackId, f: impl FnOnce(GcScope<'_>) -> R, ) -> R
Examples found in repository?
26fn alloc_static(
27 heap: &mut GcHeap,
28 stack_id: GcScopeStackId,
29 value: i32,
30) -> GcResult<GcRef<StaticNode>> {
31 heap.with_new_scope(stack_id, |ctx| {
32 let r = ctx
33 .alloc_local(StaticNode { _value: value })
34 .map_err(|(err, _)| err)
35 .map(|gc| gc.into_raw());
36 ctx.clear();
37 r
38 })
39}
40
41fn alloc_other(
42 heap: &mut GcHeap,
43 stack_id: GcScopeStackId,
44 value: i32,
45) -> GcResult<GcRef<OtherNode>> {
46 heap.with_new_scope(stack_id, |ctx| {
47 let r = ctx
48 .alloc_local(OtherNode { _value: value })
49 .map_err(|(err, _)| err)
50 .map(|gc| gc.into_raw());
51 ctx.clear();
52 r
53 })
54}Source§impl GcHeap
impl GcHeap
pub fn create_trace_ctx(&self, cap: usize) -> GcTraceCtx<'_>
Sourcepub fn trace_node(&self, node: NonNull<GcHead>, gcx: &mut GcTraceCtx<'_>)
pub fn trace_node(&self, node: NonNull<GcHead>, gcx: &mut GcTraceCtx<'_>)
Trace direct children of a node into the given trace context
pub fn traverse_start(&mut self, partition_id: GcPartitionId)
Sourcepub fn traverse(
&mut self,
node: NonNull<GcHead>,
filter: Option<GcPartitionId>,
callback: impl FnMut(NonNull<GcHead>, Option<NonNull<GcHead>>),
)
pub fn traverse( &mut self, node: NonNull<GcHead>, filter: Option<GcPartitionId>, callback: impl FnMut(NonNull<GcHead>, Option<NonNull<GcHead>>), )
Traverses the node tree starting at node in depth-first order,
invoking callback on each visited node with its optional parent.
If filter is Some, only nodes in the specified partition are visited.
Source§impl GcHeap
impl GcHeap
Sourcepub fn downgrade<T: GcNode>(&mut self, gc_ref: &GcRef<T>) -> GcWeak<T>
pub fn downgrade<T: GcNode>(&mut self, gc_ref: &GcRef<T>) -> GcWeak<T>
Create weak reference.
Examples found in repository?
76fn demonstrate_weak_references(
77 heap: &mut GcHeap,
78 partition: gc_lite::GcPartitionId,
79) -> GcResult<()> {
80 println!("1. Create strong and weak references...");
81
82 let strong_ref =
83 unsafe { heap.alloc_root_raw(partition, MyString(String::from("Strong Reference Data"))) }
84 .map_err(|(err, _)| err)?;
85
86 let weak_ref = heap.downgrade(&strong_ref);
87 println!(" Created strong reference: {:?}", strong_ref);
88 println!(" Created weak reference: {:?}", weak_ref);
89
90 // Upgrade weak reference
91 println!("\n2. Upgrade weak reference...");
92 match weak_ref.upgrade(heap) {
93 Some(upgraded) => {
94 let data = &*upgraded;
95 println!(" Weak reference upgrade successful: '{}'", data);
96 assert_eq!(data, "Strong Reference Data");
97 }
98 None => println!(" Weak reference upgrade failed"),
99 }
100
101 // Try upgrading after releasing strong reference
102 println!("\n3. Upgrade weak reference after releasing strong reference...");
103 heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
104
105 match weak_ref.upgrade(heap) {
106 Some(_) => {
107 println!(" Weak reference can still be upgraded (object may still be in memory)")
108 }
109 None => println!(" Weak reference upgrade failed (object has been collected)"),
110 }
111
112 Ok(())
113}More examples
47fn main() -> GcResult<()> {
48 println!("=== Basic usage example of partitioned garbage collection system ===");
49
50 // Create garbage collection context
51 let mut heap = GcHeap::new(&GC_TYPE_REGISTRY);
52
53 println!("Initial state:");
54 println!(" Number of partitions: {}", heap.partition_ids().len());
55
56 // Create two partitions
57 println!("\nCreate partitions:");
58 let partition1 = heap.create_partition(64 * 1024, 16 * 1024);
59 let partition2 = heap.create_partition(64 * 1024, 16 * 1024);
60 println!(" Created partition1: {:?}", partition1);
61 println!(" Created partition2: {:?}", partition2);
62 println!(" Number of partitions: {}", heap.partition_ids().len());
63
64 // Allocate objects in partition1
65 println!("\nAllocate objects in partition1:");
66 let obj1 = unsafe { heap.alloc_raw(partition1, MyString(String::from("Hello"))) }
67 .map_err(|(err, _)| err)?;
68 let obj2 = unsafe { heap.alloc_raw(partition1, MyI32(42)) }.map_err(|(err, _)| err)?;
69 let obj3 = unsafe { heap.alloc_raw(partition1, MyString(String::from("VectorData"))) }
70 .map_err(|(err, _)| err)?;
71
72 println!(" Created string: '{}'", unsafe { obj1.as_ref() });
73 println!(" Created number: {}", unsafe { obj2.as_ref() });
74 println!(" Created string: '{}'", unsafe { obj3.as_ref() });
75
76 // Allocate objects in partition2
77 println!("\nAllocate objects in partition2:");
78 let obj4 = unsafe { heap.alloc_raw(partition2, MyString(String::from("World"))) }
79 .map_err(|(err, _)| err)?;
80 let obj5 = unsafe { heap.alloc_raw(partition2, MyI32(99)) }.map_err(|(err, _)| err)?;
81
82 println!(" Created string: '{}'", unsafe { obj4.as_ref() });
83 println!(" Created number: {}", unsafe { obj5.as_ref() });
84
85 // Display partition status
86 println!("\nPartition status:");
87 for partition_id in heap.partition_ids() {
88 if let Some(partition) = heap.partition(partition_id) {
89 let limit = heap.memory_limit();
90 let usage = if limit > 0 {
91 format!(
92 "{}/{} bytes ({:.1}%)",
93 partition.memory_used(),
94 limit,
95 (partition.memory_used() as f64 / limit as f64) * 100.0
96 )
97 } else {
98 format!("{}/∞ bytes", partition.memory_used())
99 };
100 println!(
101 " {:?}: {} [自动GC: {}]",
102 partition_id,
103 usage,
104 if heap.gc_threshold() > 0 {
105 "Enabled"
106 } else {
107 "Disabled"
108 }
109 );
110 }
111 }
112
113 // Root objects are now implicitly managed by stack variables (e.g., obj1, obj2).
114 // No explicit `set_root` calls are needed for them.
115 println!("\nRoot objects are held by variables:");
116 println!(" Roots: obj1, obj2, obj3, obj4, obj5");
117
118 // Manually trigger garbage collection for partition1
119 println!("\nManually trigger garbage collection for partition1...");
120 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
121 println!(" Collected {} bytes", freed);
122
123 // Verify root objects are still valid
124 println!("\nVerify partition1 root objects are still valid:");
125 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
126 println!(" Object2: {}", unsafe { obj2.as_ref() });
127
128 // Manually trigger garbage collection for partition2
129 println!("\nManually trigger garbage collection for partition2...");
130 let freed = heap.garbage_collect(partition2, GcHeap::DUMMY_DISPOSE_CALLBACK);
131 println!(" Collected {} bytes", freed);
132
133 // Verify partition2 root objects are still valid
134 println!("\nVerify partition2 root objects are still valid:");
135 println!(" Object4: '{}'", unsafe { obj4.as_ref() });
136
137 // Trigger garbage collection for partition1 again to collect unreferenced objects
138 println!("\nTrigger garbage collection for partition1 again...");
139 // obj2 is no longer explicitly un-rooted, but we can simulate it going out of scope
140 // to test collection. For this example, we'll just collect other garbage.
141 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
142 println!(" Collected {} bytes", freed);
143
144 // Verify remaining root objects are still valid
145 println!("\nVerify remaining root objects are still valid:");
146 println!(" Object1: '{}'", unsafe { obj1.as_ref() });
147 println!(" Object2: {} (still a root)", unsafe { obj2.as_ref() });
148
149 // Demonstrate automatic garbage collection
150 println!("\nDemonstrate automatic garbage collection...");
151
152 // Create a small partition to demonstrate automatic GC
153 let small_partition = heap.create_partition(64 * 1024, 16 * 1024);
154
155 // Allocate multiple objects to fill partition
156 for i in 0..5 {
157 let _obj = unsafe { heap.alloc_raw(small_partition, MyString(format!("Object {}", i))) }
158 .map_err(|(err, _)| err)?;
159 }
160
161 println!(" Allocated 5 objects in small partition");
162
163 // Demonstrate weak references
164 println!("\nDemonstrate weak references:");
165 let weak_ref = heap.downgrade(&obj1);
166 println!(" Created weak reference: {:?}", weak_ref);
167
168 // Upgrade weak reference
169 match weak_ref.upgrade(&heap) {
170 Some(strong_ref) => {
171 println!(" Weak reference upgrade successful: '{}'", &*strong_ref);
172 }
173 None => {
174 println!(" Weak reference upgrade failed");
175 }
176 }
177
178 // Demonstrate complex types with GC references
179 println!("\nDemonstrate complex types with GC references:");
180 let mut node1 =
181 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 1")) }.map_err(|(err, _)| err)?;
182 let mut node2 =
183 unsafe { heap.alloc_raw(partition1, TestNode::new("Node 2")) }.map_err(|(err, _)| err)?;
184
185 // Establish references between nodes
186 {
187 unsafe {
188 node1.with_write_barrier(&mut heap, |n| n.add_child(node2));
189 }
190 unsafe {
191 node2.with_write_barrier(&mut heap, |n| n.add_child(node1));
192 }
193 }
194
195 println!(" Created node1: {}", unsafe { node1.as_ref() });
196 println!(" Created node2: {}", unsafe { node2.as_ref() });
197
198 // Trigger garbage collection, verify circular references are handled correctly
199 println!("\nGarbage collection for handling circular references...");
200 let freed = heap.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
201 println!(" 回收了 {} 字节内存", freed);
202
203 // Demonstrate partition deletion
204 println!("\nDemonstrate partition deletion:");
205
206 // Create an empty partition
207 let empty_partition = heap.create_partition(64 * 1024, 16 * 1024);
208 println!(" Created empty partition: {:?}", empty_partition);
209
210 // Delete empty partition
211 heap.remove_partition(empty_partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
212 println!(" Deleted empty partition successfully");
213
214 // Delete non-empty partition
215 heap.remove_partition(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
216 println!(" Deleted non-empty partition successfully");
217
218 println!("\nExample completed!");
219 Ok(())
220}