1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
//! 内存分配 API。
//!
//! 在给定程序中,标准库具有一个 `global` 内存分配器,例如 `Box<T>` 和 `Vec<T>` 就会使用它。
//!
//! 当前未指定默认的分配器。
//! 但是,默认情况下,保证像 cdylib 和 staticlib 这样的库都使用 [`System`]。
//!
//! # `#[global_allocator]` 属性
//!
//! 此属性允许配置分配器的选择。
//! 您可以使用它来实现一个完全自定义的 alloc 分配器,以将所有默认分配请求路由到自定义对象。
//!
//!
//! ```rust
//! use std::alloc::{GlobalAlloc, System, Layout};
//!
//! struct MyAllocator;
//!
//! unsafe impl GlobalAlloc for MyAllocator {
//! unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
//! System.alloc(layout)
//! }
//!
//! unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
//! System.dealloc(ptr, layout)
//! }
//! }
//!
//! #[global_allocator]
//! static GLOBAL: MyAllocator = MyAllocator;
//!
//! fn main() {
//! // 该 `Vec` 将通过上面的 `GLOBAL` 分配内存
//! let mut v = Vec::new();
//! v.push(1);
//! }
//! ```
//!
//! 该属性用于其类型实现 [`GlobalAlloc`] trait 的 `static` 项。
//! 可以由外部库提供此类型:
//!
//! ```rust,ignore (demonstrates crates.io usage)
//! use jemallocator::Jemalloc;
//!
//! #[global_allocator]
//! static GLOBAL: Jemalloc = Jemalloc;
//!
//! fn main() {}
//! ```
//!
//! `#[global_allocator]` 只能在 crate 或其递归依赖性中使用一次。
//!
//!
//!
#![deny(unsafe_op_in_unsafe_fn)]
#![stable(feature = "alloc_module", since = "1.28.0")]
use core::intrinsics;
use core::ptr::NonNull;
use core::sync::atomic::{AtomicPtr, Ordering};
use core::{mem, ptr};
#[stable(feature = "alloc_module", since = "1.28.0")]
#[doc(inline)]
pub use alloc_crate::alloc::*;
/// 操作系统提供的默认内存分配器。
///
/// 它基于 Unix 平台上的 `malloc` 和 Windows 上的 `HeapAlloc`,以及相关的函数。
/// 但是,将支持系统分配器与 `System` 混合使用是无效的,因为此实现可能包括额外的工作,例如提供比支持系统分配器直接提供的对齐更大的对齐请求。
///
///
/// 此类型默认情况下实现 `GlobalAlloc` trait 和 Rust 程序,就像它们具有以下定义一样:
///
/// ```rust
/// use std::alloc::System;
///
/// #[global_allocator]
/// static A: System = System;
///
/// fn main() {
/// let a = Box::new(4); // 从系统分配器分配。
/// println!("{a}");
/// }
/// ```
///
/// 如果愿意,还可以围绕 `System` 定义自己的包装器,例如跟踪分配的所有字节数:
///
/// ```rust
/// use std::alloc::{System, GlobalAlloc, Layout};
/// use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
///
/// struct Counter;
///
/// static ALLOCATED: AtomicUsize = AtomicUsize::new(0);
///
/// unsafe impl GlobalAlloc for Counter {
/// unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
/// let ret = System.alloc(layout);
/// if !ret.is_null() {
/// ALLOCATED.fetch_add(layout.size(), Relaxed);
/// }
/// ret
/// }
///
/// unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
/// System.dealloc(ptr, layout);
/// ALLOCATED.fetch_sub(layout.size(), Relaxed);
/// }
/// }
///
/// #[global_allocator]
/// static A: Counter = Counter;
///
/// fn main() {
/// println!("allocated bytes before main: {}", ALLOCATED.load(Relaxed));
/// }
/// ```
///
/// 它也可以直接用于独立于 Rust 程序选择的分配器来分配内存。
/// 例如,如果 Rust 程序选择使用 jemalloc 作为分配器,则 `System` 仍将使用 `malloc` 和 `HeapAlloc` 分配内存。
///
///
///
///
///
///
#[stable(feature = "alloc_system_type", since = "1.28.0")]
#[derive(Debug, Default, Copy, Clone)]
pub struct System;
impl System {
#[inline]
fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
match layout.size() {
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
// SAFETY: `layout` 的大小不为零,
size => unsafe {
let raw_ptr = if zeroed {
GlobalAlloc::alloc_zeroed(self, layout)
} else {
GlobalAlloc::alloc(self, layout)
};
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
Ok(NonNull::slice_from_raw_parts(ptr, size))
},
}
}
// SAFETY: 与 `Allocator::grow` 相同
#[inline]
unsafe fn grow_impl(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
zeroed: bool,
) -> Result<NonNull<[u8]>, AllocError> {
debug_assert!(
new_layout.size() >= old_layout.size(),
"`new_layout.size()` must be greater than or equal to `old_layout.size()`"
);
match old_layout.size() {
0 => self.alloc_impl(new_layout, zeroed),
// SAFETY: `new_size` 为非零值,因为 `new_size` 大于或等于安全条件所要求的 `old_size`,并且 `old_size == 0` 的情况在先前的匹配项 arm 中进行了处理。
// 调用者必须遵守的其他条件
//
old_size if old_layout.align() == new_layout.align() => unsafe {
let new_size = new_layout.size();
// `realloc` 可能会检查 `new_size >= old_layout.size()` 或类似的东西。
intrinsics::assume(new_size >= old_layout.size());
let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size);
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
if zeroed {
raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
}
Ok(NonNull::slice_from_raw_parts(ptr, new_size))
},
// SAFETY: 因为 `new_layout.size()` 必须大于或等于 `old_size`,所以旧的和新的内存分配对于 `old_size` 字节的读取和写入均有效。
// 另外,由于尚未分配旧分配,因此它不能与 `new_ptr` 重叠。
// 因此,调用 `copy_nonoverlapping` 是安全的。
// 调用者必须遵守 `dealloc` 的安全保证。
//
old_size => unsafe {
let new_ptr = self.alloc_impl(new_layout, zeroed)?;
ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size);
Allocator::deallocate(self, ptr, old_layout);
Ok(new_ptr)
},
}
}
}
// Allocator impl 检查布局大小是否为非零,并将其转发到 `std::sys::*::alloc` 中的 GlobalAlloc impl。
//
#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl Allocator for System {
#[inline]
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
self.alloc_impl(layout, false)
}
#[inline]
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
self.alloc_impl(layout, true)
}
#[inline]
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
if layout.size() != 0 {
// SAFETY: `layout` 的大小非零,调用者必须保持其他条件
//
unsafe { GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) }
}
}
#[inline]
unsafe fn grow(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
// SAFETY: 调用者必须遵守所有条件
unsafe { self.grow_impl(ptr, old_layout, new_layout, false) }
}
#[inline]
unsafe fn grow_zeroed(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
// SAFETY: 调用者必须遵守所有条件
unsafe { self.grow_impl(ptr, old_layout, new_layout, true) }
}
#[inline]
unsafe fn shrink(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
debug_assert!(
new_layout.size() <= old_layout.size(),
"`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
);
match new_layout.size() {
// SAFETY: 调用者必须遵守条件
0 => unsafe {
Allocator::deallocate(self, ptr, old_layout);
Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0))
},
// SAFETY: `new_size` 不为零。调用者必须遵守的其他条件
new_size if old_layout.align() == new_layout.align() => unsafe {
// `realloc` 可能会检查 `new_size <= old_layout.size()` 或类似的东西。
intrinsics::assume(new_size <= old_layout.size());
let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size);
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
Ok(NonNull::slice_from_raw_parts(ptr, new_size))
},
// SAFETY: 因为 `new_size` 必须小于或等于 `old_layout.size()`,所以旧的和新的内存分配对于 `new_size` 字节的读取和写入均有效。
// 另外,由于尚未分配旧分配,因此它不能与 `new_ptr` 重叠。
// 因此,调用 `copy_nonoverlapping` 是安全的。
// 调用者必须遵守 `dealloc` 的安全保证。
//
new_size => unsafe {
let new_ptr = Allocator::allocate(self, new_layout)?;
ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size);
Allocator::deallocate(self, ptr, old_layout);
Ok(new_ptr)
},
}
}
}
static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
/// 注册一个自定义分配错误钩子,替换以前注册的任何错误。
///
/// 当可靠的内存分配失败时 (在运行时中止之前),将调用分配错误钩子。
/// 默认的钩子将消息显示为标准错误,但是可以使用 [`set_alloc_error_hook`] 和 [`take_alloc_error_hook`] 函数自定义此行为。
///
///
/// 钩子带有 `Layout` 结构体,该结构体包含有关失败分配的信息。
///
/// 分配错误钩子是一个全局资源。
///
/// # Examples
///
/// ```
/// #![feature(alloc_error_hook)]
///
/// use std::alloc::{Layout, set_alloc_error_hook};
///
/// fn custom_alloc_error_hook(layout: Layout) {
/// panic!("memory allocation of {} bytes failed", layout.size());
/// }
///
/// set_alloc_error_hook(custom_alloc_error_hook);
/// ```
///
///
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn set_alloc_error_hook(hook: fn(Layout)) {
HOOK.store(hook as *mut (), Ordering::SeqCst);
}
/// 注销当前分配的错误钩子,并返回它。
///
/// *另请参见函数 [`set_alloc_error_hook`]。*
///
/// 如果没有注册自定义钩子,将返回默认钩子。
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn take_alloc_error_hook() -> fn(Layout) {
let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }
}
fn default_alloc_error_hook(layout: Layout) {
extern "Rust" {
// 该符号由 __rust_alloc_error_handler 旁边的 rustc 发出。
// 它的值取决于 - Zoom={panic,abort} 编译器选项。
static __rust_alloc_error_handler_should_panic: u8;
}
#[allow(unused_unsafe)]
if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
panic!("memory allocation of {} bytes failed", layout.size());
} else {
rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
}
}
#[cfg(not(test))]
#[doc(hidden)]
#[alloc_error_handler]
#[unstable(feature = "alloc_internals", issue = "none")]
pub fn rust_oom(layout: Layout) -> ! {
let hook = HOOK.load(Ordering::SeqCst);
let hook: fn(Layout) =
if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } };
hook(layout);
crate::process::abort()
}
#[cfg(not(test))]
#[doc(hidden)]
#[allow(unused_attributes)]
#[unstable(feature = "alloc_internals", issue = "none")]
pub mod __default_lib_allocator {
use super::{GlobalAlloc, Layout, System};
// 当没有 `#[global_allocator]` 属性时,这些魔术符号名称将用作实现 `__rust_alloc` etc 符号 (请参见 `src/liballoc/alloc.rs`) 的后备。
//
//
// 用于符号名称 src/librustc_ast/expand/allocator.rs 用于签名 src/librustc_allocator/lib.rs
//
// 链接指令作为当前编译器分配器 ABI 的一部分提供
//
#[rustc_std_internal_symbol]
pub unsafe extern "C" fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
// SAFETY: 请参见 `Layout::from_size_align` 和 `GlobalAlloc::alloc` 的预期保证。
//
unsafe {
let layout = Layout::from_size_align_unchecked(size, align);
System.alloc(layout)
}
}
#[rustc_std_internal_symbol]
pub unsafe extern "C" fn __rdl_dealloc(ptr: *mut u8, size: usize, align: usize) {
// SAFETY: 请参见 `Layout::from_size_align` 和 `GlobalAlloc::dealloc` 的预期保证。
//
unsafe { System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) }
}
#[rustc_std_internal_symbol]
pub unsafe extern "C" fn __rdl_realloc(
ptr: *mut u8,
old_size: usize,
align: usize,
new_size: usize,
) -> *mut u8 {
// SAFETY: 请参见 `Layout::from_size_align` 和 `GlobalAlloc::realloc` 的预期保证。
//
unsafe {
let old_layout = Layout::from_size_align_unchecked(old_size, align);
System.realloc(ptr, old_layout, new_size)
}
}
#[rustc_std_internal_symbol]
pub unsafe extern "C" fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
// SAFETY: 请参见 `Layout::from_size_align` 和 `GlobalAlloc::alloc_zeroed` 的预期保证。
//
unsafe {
let layout = Layout::from_size_align_unchecked(size, align);
System.alloc_zeroed(layout)
}
}
}