Function bacon_rajan_cc::collect::collect_cycles [] [src]

pub fn collect_cycles()

Invoke cycle collection for all Cc<T>s on this thread.

You may wish to do this when the roots buffer reaches a certain size, when memory is low, or at opportune moments within your application (such as when the user has been inactive for n seconds in a GUI application).

This happens in three phases:

  1. mark_roots: We mark the roots and decrement reference counts as we go. This is optimistically removing the strong references held by the potentially dead cycles.

  2. scan_roots: Then we perform a second traversal which marks the garbage nodes with a reference count of 0 as White and the non-garbage nodes with a reference count > 0 as Black. The latter group's reference count is restored to its previous value from before step (1).

  3. collect_roots: Finally, the buffer of possible dead cycle roots is emptied and members of dead cycles (White nodes) are dropped.

use bacon_rajan_cc::{Cc, Trace, Tracer, collect_cycles};
use std::cell::RefCell;

// The number of Gadgets allocated at any given time.
thread_local!(static GADGET_COUNT: RefCell<usize> = RefCell::new(0));

struct Gadget {
    parent: Option<Cc<RefCell<Gadget>>>,
    children: Vec<Cc<RefCell<Gadget>>>,
    // ...
}

impl Gadget {
    fn new() -> Gadget {
        GADGET_COUNT.with(|c| *c.borrow_mut() += 1);
        Gadget { parent: None, children: vec!() }
    }
}

impl Trace for Gadget {
    fn trace(&mut self, tracer: &mut Tracer) {
        if let Some(ref mut p) = self.parent {
            tracer(p);
        }
        for child in &mut self.children {
            tracer(child);
        }
    }
}

impl Drop for Gadget {
    fn drop(&mut self) {
        GADGET_COUNT.with(|c| *c.borrow_mut() -= 1);
    }
}

fn add_child(parent: &mut Cc<RefCell<Gadget>>) -> Cc<RefCell<Gadget>> {
    let child = Cc::new(RefCell::new(Gadget::new()));
    child.borrow_mut().parent = Some(parent.clone());
    parent.borrow_mut().children.push(child.clone());
    child
}

pub fn main() {
    // Initially, no gadgets.
    GADGET_COUNT.with(|c| assert_eq!(*c.borrow(), 0));

    {
        // Create cycles.

        let mut parent = Cc::new(RefCell::new(Gadget::new()));
        for _ in 0..10 {
            add_child(&mut parent);
        }

        // We created 1 parent and 10 child gadgets.
        GADGET_COUNT.with(|c| assert_eq!(*c.borrow(), 11));
    }

    // The members of the cycle are now dead, but because of the cycles
    // could not be eagerly collected.
    GADGET_COUNT.with(|c| assert_eq!(*c.borrow(), 11));

    // After calling `collect_cycles`, the cycles are detected and the
    // members of the dead cycles are dropped.
    collect_cycles();
    GADGET_COUNT.with(|c| assert_eq!(*c.borrow(), 0));
}