Rust安全指针,如何回收堆?

文摘   2024-11-05 13:16   湖北  

点击上方蓝字 江湖评谈设为关注/星标




前言

Rust内存安全,到底是如何确保安全的呢?堆上的数据,对于托管语言比如C# ,它是由GC来对堆上的数据进行回收。如果在Rust堆上分配数据,它的堆是如何回收的呢?看下Rustc智能指针Box::new的过程。

原理

例子:

fn main() {    let b = Box::new(5);    println!("b = {}", b);}

这里的运行过程:通过智能指针Box::new分配了一个堆指针,然后把数值5存储到这个堆指针里面。当前的main函数运行完成的时候,释放掉堆空间。

运行原理呢,Box::new会调用exchange_malloc函数分配一个堆指针,exchange_malloc的原型如下:

//https://github.com/rust-lang/rust/blob/1.82.0/library/alloc/src/alloc.rs/// The allocator for unique pointers.#[cfg(all(not(no_global_oom_handling), not(test)))]#[lang = "exchange_malloc"]#[inline]unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {    let layout = unsafe { Layout::from_size_align_unchecked(size, align) };    match Global.allocate(layout) {        Ok(ptr) => ptr.as_mut_ptr(),        Err(_) => handle_alloc_error(layout),    }}

把这个堆指针返回,然后在堆指针指向的地方赋值为5。这里用的是寄存器保存了堆指针,进行了地址赋值:

mov dword ptr [rax], 0x5

最后当main函数返回之前的指令ret处调用drop_in_place函数释放掉堆空间。drop_in_place函数原型:

//https://github.com/rust-lang/rust/blob/1.82.0/library/core/src/ptr/mod.rs#l574pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {    // Code here does not matter - this is replaced by the    // real drop glue by the compiler.
// SAFETY: see comment above unsafe { drop_in_place(to_drop) }}

它这里强调的是一个作用域,在main函数的作用域之内堆指针是有效的,离开了就立刻释放掉。

底层

为了验证下以上说法,这里动用下lldb。通过cargo build编译下以上例子,在target/debug目录下生成了带有调试符号的二进制。此时附加下lldb。在main下端,会直接运行到例子main入口处。

我们很清楚的看到了Box::new调用了exchange_malloc,同样的在main作用域快要结束(也就是main的结尾处),我们看到了drop_in_place调用:

结尾

总体上来说,rust堆空间操作分为三部分。其一:堆空间申请。其二:堆空间赋值修改。其三:堆空间的释放。一般的对于托管语言,堆空间的申请和释放通过GC来进行。Rust智能指针通过用域的判断,来申请和释放当前堆的空间。从而避免了自带一个GC垃圾回收器这种较为沉重的设计而进行的操作。

往期精彩回顾

.NET9/Rust编译对比

C++安全指针,Rust用处何在?


江湖评谈
记录,分享,自由。
 最新文章