[−][src]Crate hulunbuir
Hulunbuir is a cross-thread garbage collector. The managed objects could be used in multithreads, and collecting process may happen in any of them.
Normally, reading or updating a managed object must lock global collector as well,
which significantly decrease multithread performance. However, Hulunbuir does not provide
common "read guard" and "write guard" interface; instead it only supports two functions:
allocate
and replace
. The first one create a managed object, and may trigger a garbage
collecting process if necessary; the second one replace the value of a managed object with
a new one provided by argument. The global collector only have to be locked during replacing
and the lock could be released when working thread owns the value. So the lock will not
become the bottleneck of performance.
Hulunbuir also provides Slot
as higher level abstraction and interface.
Basic usage
use hulunbuir::{Address, Collector, Keep}; // create a managed type struct ListNode(i32, Option<Address>); // implement Keep for it, so it could be managed impl Keep for ListNode { fn with_keep<F: FnOnce(&[Address])>(&self, keep: F) { // each node keeps only its tail, so call `keep` with it... if let Some(tail) = self.1.to_owned() { // ...if the node has tail keep(&[tail]) } } } fn main() { // create a collector with 128 slots available let mut collector = Collector::new(128); let root = collector.allocate(ListNode(0, None)).unwrap(); collector.set_root(root.clone()); let tail = collector.allocate(ListNode(1, None)).unwrap(); // replace root node out with something not important let mut root_node = collector.replace(&root, ListNode(42, None)).unwrap(); root_node.1 = Some(tail); // replace root node back let _ = collector.replace(&root, root_node).unwrap(); let _orphan = collector.allocate(ListNode(2, None)).unwrap(); // before collecting... assert_eq!(collector.alive_count(), 3); collector.collect(); // after collecting... assert_eq!(collector.alive_count(), 2); }
This replace
-based object updating strategy is suitable for simple single-thread usage.
The collector will work correctly only when no garbage collection happens when any
"real" object is replaced out, which means, when any of them is replaced out:
- no explicit calling to
Collector::collect
- no calling to
Collector::allocate
, since it may trigger collection as well if there's no slot available
In multithreading context, none of above could be archieved since each thread has no idea
about what the others are doing. So more complicated strategy must be introduced. Hulunbuir
provides slot
module for this purpose, but you are free to develop your own one.
Re-exports
pub use crate::error::Error; |
Modules
error | Errors. |
slot | Slot-based abstraction for automatic dependency caching and thread parking. |
Structs
Address | Virtual memory address token. |
Collector | Memory manager for allocation and garbage collection. |
Traits
Keep | Required trait for managed objects' type. |