Shredder: Garbage Collection as a Library for Rust

栏目: IT技术 · 发布时间: 4年前

内容简介:I'm excited to announceIn this example we hadThe only ergonomic issue to note is the need for guard objects. In

I'm excited to announce shredder , a library for Rust that provides a garbage collected smart pointer, Gc . This smart pointer is useful in the same sorts of situations as Rc , but can handle reference cycles. It's available on crates.io and Github . Here's how you could use it:

use std::cell::RefCell;

use shredder::{
    Gc, Scan,
    run_with_gc_cleanup,
    number_of_active_handles,
    number_of_tracked_allocations,
};

#[derive(Scan)]
struct Node {
    data: String,
    directed_edges: Vec<Gc<RefCell<Node>>>,
}

fn main() {
    // Using `run_with_gc_cleanup` is good practice
    // (it helps ensure destructors are run)
    run_with_gc_cleanup(|| {
        let a = Gc::new(RefCell::new(Node {
            data: "A".to_string(),
            directed_edges: Vec::new(),
        }));

        let b = Gc::new(RefCell::new(Node {
            data: "B".to_string(),
            directed_edges: Vec::new(),
        }));

        // Usually would need `get` for `Gc` data,
        // but `RefCell` is a special case
        a.borrow_mut().directed_edges.push(b.clone());
        b.borrow_mut().directed_edges.push(a);
        // We now have cyclical data!
    });
    // Everything was cleaned up!
    assert_eq!(number_of_tracked_allocations(), 0);
    assert_eq!(number_of_active_handles(), 0);
}

In this example we had #[derive(Scan)] on our struct. By implementing this trait, we let shredder know how it can find what Gc handles this data contains. This is an essential part of the tracing garbage collection that shredder implements. After we've done that, using the smart pointer is basically just plug and play!

The only ergonomic issue to note is the need for guard objects. In shredder , you always need a guard object when accessing data inside a Gc . Usually you need to use .get to get a GcGuard . (Guarded access is key to implementing shredder 's guarantees in a performant way.) Now, notice how we didn't have to do this in the above example. In general, Gc is only useful with interior mutability, so Gc<RefCell<?>> , Gc<Mutex<?>> and Gc<RwLock<?>> have special methods that let you skip this step (see documentation for more details).

People have experimented with garbage collection in Rust before, but I wasn't happy with existing libraries. I do not believe there is an existing Rust library providing an easy to use garbage collection solution that can robustly work in concurrent programs, as well as handle non- 'static data.   shredder does that and more. Let me break down what I consider the best features of shredder . (If you're interested in a deep dive into how it all works, I hope to provide a follow post on the design.)

1 Safety First)It should be impossible to cause unsafe behavior in safe code using shredder . The only unsafe parts of the API are writing manual implementations of the core traits: Scan , GcSafe and Finalize . I've done my best to ensure they have complete documentation explaining how to implement them safely.

2 Ergonomics Second)I believe a lot of the existing solutions are fairly hard to grok, requiring complex macros or weird setups with lifetimes. In shredder , Gc is basically just a fancy Arc , and I hope that makes the library easier to use. (And in the future I even want to make the guard object optional, assuming I can make it safe and performant!)

3 Ready for Fearless Concurrency) shredder was always designed to deal with multithreaded programs. You can send a Gc around just as if it was an Arc , and I think that's really cool! Keeping with this, I've designed the collector so that even if a thread holds onto a ton of GcGuard s, collection can still proceed as normal. The only operation that should implicitly block on collection in shredder is calling .get (or one of the helper methods wrapping .get ).

4 Seamless Destruction)By default, Gc::new only takes 'static data, and when it is found to be unreachable, it is dropped and its destructor is called. (There are safety checks in place to prevent you from exploiting cyclical data in the destructor.) This saves users the pain of having to deal with Finalize in the common case. The run_with_gc_cleanup method is also provided, and helps ensure destructors are run at the end of your program.

5 Clean Finalization)Sometimes, however, you need non- 'static data. Unfortunately, since we may scan data after lifetimes have expired, you cannot use raw references. Instead you must replace &'a T with R<'a, T> and &'a mut T with RMut<'a, T> . Outside of Scan and Finalize implementations, these can be used as if they were regular references. Speaking of Finalize , if you implement it, and use Gc::new_with_finalizer , then you can use unsafe code to define code to be run right before your data is deallocated.

6 Concurrent Collection and Destruction)Finally, as a nice side effect of shredder s design, automatic collection always happens in a background thread, and hopefully doesn't implement your regular processing too badly. Same goes for running destructors, which might actually be a performance win if your destructors are expensive.

shredder isn't perfect. It needs a lot more performance optimization, and I think the background collection can become even more concurrent in the future. It also has a non-trivial memory overhead. And of course it is very new and immature.

However, I think that's okay for now. I designed shredder to be another tool in the Rust programmer's toolbox. Gc is a very extreme escape hatch that lets you escape usual ownership rules. It's something that should be used carefully in small doses, where giving up the superior performance of RAII memory management is worth it. (Perhaps for user provided data with unpredictable loops, or interestingly shaped graphs.) I'm excited to see what people can do with it!

It's available on crates.io and Github . (If you've read this far, maybe you're interested in contributing? I've put some issues on the Github, and that might be a good place to start!)


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

软件预构艺术(中文版)

软件预构艺术(中文版)

Ken Pugh / O'Reilly Taiwan公司 / 东南大学 / 2010-6 / 26.00元

利用经验累积而得到的洞察力开发新的解决方案被称为预构。透过重构而获得的专业知识也属于这类经验,而预构的词源即重构。重构是修改程序或软件系统内部结构的实践,以此在保留其现有行为的基础上改良设计。重构的原因有多种:方便后期增加功能、提高可维护性、提升性能。 本书作者是经验老道的软件开发人员。书中,作者运用他个人和其他众多开发人员的丰富经验,展示由其推衍而得的各项实践方针。这些方针把优秀的开发人员......一起来看看 《软件预构艺术(中文版)》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

随机密码生成器
随机密码生成器

多种字符组合密码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具