mirror of
https://github.com/servo/servo.git
synced 2025-09-22 21:00:14 +01:00
Add an off-by-default allocator mode that tracks all live allocations with sizes and associated stack traces. We also track if each allocation is visited as part of a measuring heap usage in `about:memory`, allowing us to report on allocations that are not tracked yet. Right now the list of untracked allocations is dumped to stdout; I have a python script coming in a separate PR which makes it easier to perform analysis on the massive output. Testing: Manually tested with `./mach build -d --features servo_allocator/allocation-tracking` and visiting about:memory. Part of: #11559 --------- Signed-off-by: Josh Matthews <josh@joshmatthews.net>
139 lines
4.2 KiB
Rust
139 lines
4.2 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
//! Selecting the default global allocator for Servo, and exposing common
|
|
//! allocator introspection APIs for memory profiling.
|
|
|
|
use std::os::raw::c_void;
|
|
|
|
#[cfg(not(feature = "allocation-tracking"))]
|
|
#[global_allocator]
|
|
static ALLOC: Allocator = Allocator;
|
|
|
|
#[cfg(feature = "allocation-tracking")]
|
|
#[global_allocator]
|
|
static ALLOC: crate::tracking::AccountingAlloc<Allocator> =
|
|
crate::tracking::AccountingAlloc::with_allocator(Allocator);
|
|
|
|
#[cfg(feature = "allocation-tracking")]
|
|
mod tracking;
|
|
|
|
pub fn dump_unmeasured() {
|
|
#[cfg(feature = "allocation-tracking")]
|
|
ALLOC.dump_unmeasured_allocations();
|
|
}
|
|
|
|
pub use crate::platform::*;
|
|
|
|
type EnclosingSizeFn = unsafe extern "C" fn(*const c_void) -> usize;
|
|
|
|
/// # Safety
|
|
/// No restrictions. The passed pointer is never dereferenced.
|
|
/// This function is only marked unsafe because the MallocSizeOfOps APIs
|
|
/// requires an unsafe function pointer.
|
|
#[cfg(feature = "allocation-tracking")]
|
|
unsafe extern "C" fn enclosing_size_impl(ptr: *const c_void) -> usize {
|
|
let (adjusted, size) = crate::ALLOC.enclosing_size(ptr);
|
|
if size != 0 {
|
|
crate::ALLOC.note_allocation(adjusted, size);
|
|
}
|
|
size
|
|
}
|
|
|
|
#[allow(non_upper_case_globals)]
|
|
#[cfg(feature = "allocation-tracking")]
|
|
pub static enclosing_size: Option<EnclosingSizeFn> = Some(crate::enclosing_size_impl);
|
|
|
|
#[allow(non_upper_case_globals)]
|
|
#[cfg(not(feature = "allocation-tracking"))]
|
|
pub static enclosing_size: Option<EnclosingSizeFn> = None;
|
|
|
|
#[cfg(not(any(windows, feature = "use-system-allocator", target_env = "ohos")))]
|
|
mod platform {
|
|
use std::os::raw::c_void;
|
|
|
|
pub use tikv_jemallocator::Jemalloc as Allocator;
|
|
|
|
/// Get the size of a heap block.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// Passing a non-heap allocated pointer to this function results in undefined behavior.
|
|
pub unsafe extern "C" fn usable_size(ptr: *const c_void) -> usize {
|
|
let size = unsafe { tikv_jemallocator::usable_size(ptr) };
|
|
#[cfg(feature = "allocation-tracking")]
|
|
crate::ALLOC.note_allocation(ptr, size);
|
|
size
|
|
}
|
|
|
|
/// Memory allocation APIs compatible with libc
|
|
pub mod libc_compat {
|
|
pub use tikv_jemalloc_sys::{free, malloc, realloc};
|
|
}
|
|
}
|
|
|
|
#[cfg(all(
|
|
not(windows),
|
|
any(feature = "use-system-allocator", target_env = "ohos")
|
|
))]
|
|
mod platform {
|
|
pub use std::alloc::System as Allocator;
|
|
use std::os::raw::c_void;
|
|
|
|
/// Get the size of a heap block.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// Passing a non-heap allocated pointer to this function results in undefined behavior.
|
|
pub unsafe extern "C" fn usable_size(ptr: *const c_void) -> usize {
|
|
#[cfg(target_vendor = "apple")]
|
|
unsafe {
|
|
let size = libc::malloc_size(ptr);
|
|
#[cfg(feature = "allocation-tracking")]
|
|
crate::ALLOC.note_allocation(ptr, size);
|
|
size
|
|
}
|
|
|
|
#[cfg(not(target_vendor = "apple"))]
|
|
unsafe {
|
|
let size = libc::malloc_usable_size(ptr as *mut _);
|
|
#[cfg(feature = "allocation-tracking")]
|
|
crate::ALLOC.note_allocation(ptr, size);
|
|
size
|
|
}
|
|
}
|
|
|
|
pub mod libc_compat {
|
|
pub use libc::{free, malloc, realloc};
|
|
}
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
mod platform {
|
|
pub use std::alloc::System as Allocator;
|
|
use std::os::raw::c_void;
|
|
|
|
use windows_sys::Win32::Foundation::FALSE;
|
|
use windows_sys::Win32::System::Memory::{GetProcessHeap, HeapSize, HeapValidate};
|
|
|
|
/// Get the size of a heap block.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// Passing a non-heap allocated pointer to this function results in undefined behavior.
|
|
pub unsafe extern "C" fn usable_size(mut ptr: *const c_void) -> usize {
|
|
unsafe {
|
|
let heap = GetProcessHeap();
|
|
|
|
if HeapValidate(heap, 0, ptr) == FALSE {
|
|
ptr = *(ptr as *const *const c_void).offset(-1)
|
|
}
|
|
|
|
let size = HeapSize(heap, 0, ptr) as usize;
|
|
#[cfg(feature = "allocation-tracking")]
|
|
crate::ALLOC.note_allocation(ptr, size);
|
|
size
|
|
}
|
|
}
|
|
}
|