rust 析构 释放内存


前言

rust中析构用Drop trait

析构≠释放内存,一般析构里放释放内存操作

析构函数里面没有释放内存操作时可以重复调用,释放内存不行->double free

先定义2个结构体,其中MyStruct包含InnerPtrInnerPtr包含一个智能指针等待释放

struct MyStruct {
    pub inner: InnerPtr,
}

impl MyStruct {
    fn new() -> Self {
        Self { inner: InnerPtr::new() }
    }
}

impl Drop for MyStruct {
    fn drop(&mut self) {
        println!("calling drop for MyStruct @ {:p}", self);
    }
}

#[derive(new)]
struct InnerPtr {
    #[new(default)]
    data: Box<u8>,
}

impl Drop for InnerPtr {
    fn drop(&mut self) {
        println!("calling drop for InnerPtr, data @ {:p}", self.data.as_mut());
    }
}

一、栈

在这里插入图片描述

forget 阻止对象脱离作用域后自动析构。drop提前析构对象,可用于提前释放锁

fn main() {
    let a = MyStruct::new();

    println!("{:p}", &a);
    println!("{:p}", &a.inner);
    println!("{:p}", &a.inner.data);
    
    // drop(a);

    mem::forget(a);
}

ManuallyDrop自己负责何时调用析构

fn main() {
    let a = MyStruct::new();
    
    let mut manual_a = ManuallyDrop::new(a);

    unsafe { ManuallyDrop::drop(&mut manual_a); }
}

二、堆

在这里插入图片描述

1.智能指针

如果只想要数据的指针而不想手动管理内存可以下面这样搞,用指针而不是引用的好处在于不用担心a的所有权发生转移导致指针不可用

fn main() {
    let mut a = Box::new(MyStruct::new());

    // 只获取对象指针 智能指针还在
    let p = a.as_mut() as *mut MyStruct;
    
    let mut b = a;

    println!("{:p}", p);
    println!("{:p}", b.as_mut());
}

智能指针转换为裸指针需要手动释放内存,由图可知需要释放2块内存,其中智能指针在析构函数里面实现了释放内存,因此最简单的方法如下:drop_in_place(p)递归调用自身和字段的析构函数释放结构体内部分配的内存,dealloc(p ...) 释放MyStruct内存

fn main() {
    let mut a = Box::new(MyStruct::new());

    // 智能指针->裸指针
    let p = Box::into_raw(a);

    unsafe {
        // 调用析构
        drop_in_place(p);
        
        // 释放内存
        dealloc(p as *mut u8, Layout::new::<MyStruct>());
    }
}

如果知道所有内存的位置也可以全用dealloc

fn main() {
    let mut a = Box::new(MyStruct::new());

    // 智能指针->裸指针
    let p = Box::into_raw(a);
    println!("{}", size_of::<MyStruct>());

    unsafe {
        // 释放内存
        dealloc((*p).inner.data.as_mut() as *mut u8, Layout::new::<u8>());
        dealloc(p as *mut u8, Layout::new::<MyStruct>());
    }
}

或者专门调用二级智能指针的drop,再释放MyStruct

fn main() {
    let mut a = Box::new(MyStruct::new());

    // 智能指针->裸指针
    let p = Box::into_raw(a);
    println!("{}", size_of::<MyStruct>());

    unsafe {
        // 调用析构
        // Inner与MyStruct的内存地址相同
        drop_in_place(p as *mut InnerPtr);
        // drop_in_place(&mut ((*p).inner));

        // 释放内存
        dealloc(p as *mut u8, Layout::new::<MyStruct>());
    }
}

2.分配器

alloc分配未初始化内存,直接调用drop会尝试释放里面的智能指针导致STATUS_HEAP_CORRUPTION,所以drop前要赋值。或者直接释放内存而不drop

fn main() {
    // 创建布局, 申请内存
    let layout = Layout::new::<MyStruct>();

    unsafe {
        let p = alloc(layout) as *mut MyStruct;
        p.write(MyStruct::new());

        // 调用对象的drop
        drop_in_place(p);
        // 释放内存
        dealloc(p as *mut u8, layout);
    }
}

分配数组方式如下,drop_in_place输入*mut [T]来析构数组所有元素,*mut [T]是一个胖指针,里面有长度信息

fn main() {
    let layout = Layout::array::<MyStruct>(3).unwrap();

    unsafe {
        let p = alloc(layout) as *mut MyStruct;
        p.write(MyStruct::new());
        p.add(1).write(MyStruct::new());
        p.add(2).write(MyStruct::new());

        // 调用对象的drop
        drop_in_place(slice_from_raw_parts_mut(p, 3));
        // 释放内存
        dealloc(p as *mut u8, layout);
    }
}
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值