7个版本
0.3.0 | 2019年9月27日 |
---|---|
0.2.4 | 2019年8月2日 |
0.2.1 | 2019年7月31日 |
0.1.0 | 2019年7月11日 |
#28 in #managed
21KB
188 行
Hulunbuir
查看 examples
文件夹以获取基本用法。
lib.rs
:
Hulunbuir 是一个跨线程垃圾收集器。管理对象可以在多线程中使用,收集过程可能发生在任何一个线程中。
通常,读取或更新管理对象必须锁定全局收集器,这会显著降低多线程性能。然而,Hulunbuir 不提供常见的 "读保护" 和 "写保护" 接口;相反,它只支持两个函数: allocate
和 replace
。第一个创建一个管理对象,如果需要,可能会触发垃圾收集过程;第二个用由参数提供的新值替换管理对象的值。全局收集器只需要在替换时锁定,当工作线程拥有该值时可以释放锁。因此,锁不会成为性能瓶颈。
Hulunbuir 还提供了 Slot
作为更高层次抽象和接口。
基本用法
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: FnMut(&Address)>(&self, mut keep: F) {
// each node keeps only its tail, so call `keep` with it...
if let Some(tail) = &self.1 {
// ...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);
}
这种基于 replace
的对象更新策略适用于简单的单线程使用。收集器将在没有任何 "真实" 对象替换时正确工作,这意味着,当其中任何一个 被替换 出来时
- 没有显式调用
Collector::collect
- 没有调用
Collector::allocate
,因为它可能会在没有槽位可用时触发收集
在多线程环境中,上述任何一种都不能实现,因为每个线程都不知道其他线程在做什么。因此,必须引入更复杂的策略。Hulunbuir 提供了 slot
模块用于此目的,但你也可以自由开发自己的模块。
依赖关系
~2MB
~46K SLoC