Open hannoman opened 23 hours ago
I tried to write a minimal example crosschecking with a wrapped global allocator, which i would expect to work:
use Ordering::Relaxed;
use std::alloc;
use std::alloc::{GlobalAlloc, Layout};
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use get_size2::GetSize;
static USED_MEMORY: AtomicUsize = AtomicUsize::new(0);
struct WrappedRustAllocator;
unsafe impl GlobalAlloc for WrappedRustAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let wrappee = alloc::System;
let size = layout.size();
let alloced = wrappee.alloc(layout);
if !alloced.is_null() {
USED_MEMORY.fetch_add(size, Relaxed);
}
alloced
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
let wrappee = alloc::System;
let size = layout.size();
wrappee.dealloc(ptr, layout);
USED_MEMORY.fetch_sub(size, Relaxed);
}
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
let wrappee = alloc::System;
let old_size = layout.size();
let realloced = wrappee.realloc(ptr, layout, new_size);
if !realloced.is_null() {
if new_size > old_size {
USED_MEMORY.fetch_add(new_size - old_size, Relaxed);
} else {
USED_MEMORY.fetch_sub(old_size - new_size, Relaxed);
}
}
realloced
}
}
#[global_allocator]
static RUST_ALLOCATOR: WrappedRustAllocator = WrappedRustAllocator;
fn main() {
let used_before = USED_MEMORY.load(Relaxed);
let x = Arc::new(42u64);
let used_after = USED_MEMORY.load(Relaxed);
let delta = used_after - used_before;
assert_eq!(x.get_heap_size(), delta);
}
I think the get_heap_size() implementation for Arc, Rc (and maybe similar types) is wrong because it doesn't account for the additional bookkeeping values these types allocate on the heap - which in these case are a strong and a weak reference count variable of size
size_of::<usize>
. Or put differently: Arc does not allocate T directly on the heap, but anArcInner<T>
which contains T and the refcounting variables. But the current implementation https://github.com/bircni/get-size2/blob/ce1477b8f7774c3163c9b253266a9da3bd2ebf1e/get-size2/src/lib.rs#L383 it resolves to a call where&**self
is a&T
, although it conceptually should be an&ArcInner<T>
.