Skip to content
This repository was archived by the owner on Jul 10, 2023. It is now read-only.
This repository was archived by the owner on Jul 10, 2023. It is now read-only.

Dealing with shared ownership (Rc and Arc) #37

@SimonSapin

Description

@SimonSapin

A central idea behind this crate is that most resources in Rust have one well-defined owner. heap_size_of_children can trace recursively and only consider owned resources. For &T references it can return zero since they usually either point to non-heap memory, or to heap memory owned by something else that will be accounted for there.

This breaks down for types like Rc<T> and Arc<T> that introduce "shared ownership". They do have heap memory that we want to count, but in a fully generic context there is no clear single point where it should be counted.

(In a more specific context there count be a "main" Rc reference for a given resource. For example, following only the "first child" and "next sibling" references in a Kuchiki tree allows traversing the whole tree without duplication.)

In the current version (90dd7e0) this crate has:

impl<T: HeapSizeOf> HeapSizeOf for Arc<T> {
    fn heap_size_of_children(&self) -> usize {
        (**self).heap_size_of_children()
    }
}

This impl is returns an incorrect number for two reasons:

  • It’s too low because it only counts the size of resources owned by T, not the size of T itself and the two reference counts that Arc holds internally. This part is easy to fix.

  • It’s too high because there could be many Arc references to the same T value, and this impl duplicates by that many times the count of memory owned by T.

    One idea that I’ve heard/read (I don’t remember from who, sorry) was to divide by the strong reference count. If all strong references are traced correctly these fractions should add up to the correct value. But the usize return type would have to be changed to f32 or f64 to get remotely accurate results, which is weird at best. And Arc::strong_count and Rc::strong_count are still #[unstable]: Tracking issue for Arc/Rc extras rust-lang/rust#28356

The current version of this crate has another impl:

impl<T> HeapSizeOf for Vec<Rc<T>> {
    fn heap_size_of_children(&self) -> usize {
        // The fate of measuring Rc<T> is still undecided, but we still want to measure
        // the space used for storing them.
        unsafe {
            heap_size_of(self.as_ptr() as *const c_void)
        }
    }
}

My understanding of it as that, in practice, when we can’t have a correct impl of HeapSizeOf, Servo sometimes implement it (incorrectly) returning zero because an underestimated answer is better(?) than no answer.

This Vec<Rc<T>> follows this idea, just making the error smaller: don’t count Rc’s but count the Vec containing them.

Still, I don’t think there’s a reason to treat Rc<T> and Arc<T> differently.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions