通过自定义Vec<T>理解Rust中的内存分配方式

博客围绕Rust展开,介绍了Rust中内存分配方式,可自定义内存分配算法并通过注解告知编译器。通过代码展示alloc和Layout的使用,解释了请求内存、分配内存、访问内存及释放内存的操作。还阐述了Rust中通过NonNull智能指针和Layout::array实现自定义Vec的方法。

Rust中一般通过syscall分配内存, 可以自定义分配内存算法,实现GlobalAlloc trait, 并通过#[global_allocator]注解告诉编译器自定义的内存分配算法。

alloc和Layout实战

在我们深入了解之前,先通过以下简单代码段对 alloc, dealloc 以及Layout对Rust内存分配有一个基本概念。

use std::alloc::{
   
   alloc, dealloc, Layout};
fn main(){
   
   
	let layout = Layout::new::<i32>();
    let ptr = unsafe {
   
    alloc(layout) } as *mut i32;

    unsafe {
   
   
        *ptr = 42;
    }

    let value = unsafe {
   
    *ptr };
    println!("value: {}", value);

    unsafe {
   
   
        dealloc(ptr as *mut u8, layout);
    }
}

下面我们对这段代码做一个解释, 看看每行代码都做了那些事情。

  1. let layout = Layout::new::<i32>();
    这行代码就像是我们预先请求了一段新的数据存储单元, 通过Layout告诉Rust我们需要一段足够大的内存来存储i32, 你也可以换成其他数据类型比如:String,Structs等等,Rust会恰到好处的处理所需的存储单元大小。
  2. let ptr = unsafe { alloc(layout) } as *mut i32 ;
    在这里我们通过调用std::alloc::alloc这个函数, 传入我们请求的内存布局, Rust会分配一块内存单元并返回这块内存的可变的i32指针 (*mut i32), 后面我们可以通过这个可变指针来修改或读取指针指向的数据.

这里使用了unsafe关键字来告诉Rust编译器在这段unsafe代码块中我们不在需要编译器来保证内存安全. 因此,内存安全完全由开发者自行控制,

  1. let value = unsafe { *ptr };
    这里我们通过unsafe代码块来访问指针指向的内存空间. 但是需要注意的是指针指向的内存空间是没有安全保障的, 可能为null, 可以通过is_null()判断. 之后打印了指针指向的value.

  2. unsafe { dealloc(ptr as *mut u8, layout) };
    通过dealloc方法释放之前申请的分配好的内存. 这里使用的mut u8指针类型来释放内存 而不是mut i32, 因为i32是申请的数据类型,也可以是String, 自定义的结构体等.

自定义Vec

Rust中的动态数组是通过NonNull智能指针, 并通过Layout::array来实现指针数组.

#![feature(allocator_api)]

use std::{
   
   alloc::Layout, ptr::NonNull};

struct Arr<T: Sized> {
   
   
    // 数据指针
    ptr: NonNull<T>,
    // 数组实际长度
    len: usize,
    // 数组容量
    cap: usize,
}

impl<T
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值