I have some fairly in-depth usage with Arc's. I am attempting to debug an Arc getting lost with (probably) some unsafe code (one Arc is not getting dropped causing a memory leak). Is there a way to debug output the specific pointer of different std::sync::Arc's so i could see exactly which one is not getting cleaned up?
For example:
use std::sync::Arc;
fn main() {
let x = Arc::new(1);
let y = x.clone();
println!("X: {:?}, Y: {:?}", x, y);
}
Outputs:
X: 1, Y: 1
But i actually want the pointer address. That way i can differentiate between the Arc's. I noticed nightly rust has Arc::as_ptr() but that too gives a pointer to the wrapped struct and not the Arc itself. Any quick tips?
The only thing contained within an Arc is a pointer to the inner structure, so they’re literally indistinguishable from each other. You could use the memory address of the Arc itself, but that will change whenever it’s moved from one place to another, like by being returned from a function.
Arc is a pointer, similar to Box, and all clones of the same Arc point to the same thing, i.e. have exact same value.
You're probably expecting Arc to have two layers of indirection — one to some Arc object, and then another to the data. This is not the case. There is only one layer of indirection: straight to where the count and the data is stored together in one place.
You could try get an address of that pointer, each individual clone of Arc, but that is futile, because it's like wanting an address of usize. It's not heap allocated, and it doesn't have a stable address.
Your code:
fn main() {
let x = Arc::new(1);
let y = x.clone();
println!("X: {:?}, Y: {:?}", x, y);
}
is equivalent of:
fn main() {
let x = 12345;
let y = 12345.clone();
println!("X: {:?}, Y: {:?}", 12345, 12345);
}
All clones of Arc are identical. The "clone" part is fake, as it doesn't create anything new, it only updates a counter.
If you have control over when your Arc<T> is created, what about Arc::downgrade()-ing to a Weak<T> pointer and stashing that Weak<T> away somewhere? Potentially using Weak::as_ptr() to get a stable pointer for use as a key.
You can then iterate over all the weak pointers to see which is still alive at some later point in your program.
For future reference: it is sometimes recommended to use Arc::clone(x) instead of x.clone() to emphasize that we're cloning the Arc rather than the underlying data. See clippy lint clone_on_ref_ptr (allowed by default).