美文网首页
Rust手动管理内存

Rust手动管理内存

作者: 黑天鹅学院 | 来源:发表于2021-11-06 10:04 被阅读0次

为了确保安全性,Rust在零抽象的基础上,限制了很多易导致潜在bug的操作,比如直接指针操作,以及长生命周期等等,但是在某些情况下,如果涉及到操作比较底层的数据,往往难免自行维护内存。

本文主要以layout库来进行手动内存维护演示。

假设要实现一个内存分配器,但是需要满足以下条件:

  • 手动从堆中申请内存
  • 手动执行内存回收
  • 内存空间能够被复用

由于要手动回收内存,可行的方案是实现一个智能指针包裹裸指针,为了将裸指针指向的内存区视为待分配的数据结构,可以采用强制类型转换。

use std::alloc::{alloc, dealloc, Layout};
use std::ops::{Deref, DerefMut};
use std::fmt;
use fmt::Debug;
use std::collections::HashMap;

#[derive(Debug)]
struct Header {
    a: i32,
}

struct Cap<T>(*mut u8, Layout, std::marker::PhantomData<T>);

impl<T> Cap<T> {
    fn new() -> Self {
        let layout = Layout::new::<T>();
        unsafe {
            let ptr = alloc(layout);
            Cap(ptr, layout, std::marker::PhantomData)
        }
    }
}

impl<T: Debug> fmt::Display for Cap<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            write!(f, "({:?})", & *(self.0 as *mut T))
        }
    }
}

impl<T> Drop for Cap<T> {
    fn drop(&mut self) {}
}

impl<T> Deref for Cap<T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe {
            & *(self.0 as *mut T)
        }
    }
}

impl<T> DerefMut for Cap<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe {
            &mut *(self.0 as *mut T)
        }
    }
}

struct MemCache<T> {
    cache_map: HashMap<usize, Vec<Cap<T>>>,
}

impl<T> MemCache<T> {
    fn new() ->Self {
        MemCache {
            cache_map: HashMap::new(),
        }
    }

    fn alloc(&mut self) -> Cap<T> {
        let obj_size = std::mem::size_of::<T>();
        match self.cache_map.get_mut(&obj_size) {
            Some(bucket) => {                
                if bucket.is_empty() {
                    return Cap::<T>::new()
                } else {
                    let ele = bucket.remove(0);
                    return ele
                }
            },
            _ => {
                return Cap::<T>::new();
            },
        }
    }

    fn drop(&mut self, d: Cap<T>) {
        let obj_size = std::mem::size_of::<T>(); 
        match self.cache_map.get_mut(&obj_size) {
            Some(bucket) => {
                bucket.push(d);
            }
            _ => {
                let mut b = Vec::new();
                b.push(d);
                self.cache_map.insert(obj_size, b);
            }
        };
    }
}

fn main() {
    let mut cache = MemCache::<Header>::new();

    let mut t1 = cache.alloc();
    t1.a = 38;
    println!("Cap {:#}", t1);
    cache.drop(t1);

    let mut t2 = cache.alloc();
    t2.a = 36;
    println!("Cap {:#}", t2);
    cache.drop(t2);
}

主要思路如下:

  • 用智能指针封装裸指针,在deref时,将裸指针转换为具体的类型
  • 释放智能指针时,用一个HashMap缓存住,在分配阶段如果有缓存则用缓存

上述的实现不能自动执行drop,需要手动执行,所以在CapDrop实现是一个空函数。

为了实现自动释放,需要在Cap中记录下MemCache,参考实现如下:

use std::fmt;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr;

use crossbeam_queue::SegQueue;
use stable_deref_trait::StableDeref;

pub trait Allocate {
    fn alloc() -> Self;
}

#[derive(Debug)]
struct Header {
    a: i32,
}

impl Allocate for Header {
    fn alloc() -> Self {
        Header {
            a: 89,
        }
    }
}

pub struct BytePool<T>
where
    T: Allocate,
{
    small_bask: SegQueue<T>,
}

pub struct ByteBuffer<'a, T: Allocate> {
    data: mem::ManuallyDrop<T>,
    pool: &'a BytePool<T>,
}

impl<T: Allocate + fmt::Debug> fmt::Debug for ByteBuffer<'_, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.data.deref())
    }
}

impl<T: Allocate + fmt::Debug> fmt::Display for ByteBuffer<'_, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.data.deref())
    }
}

impl<T: Allocate> Default for BytePool<T> {
    fn default() -> Self {
        BytePool::<T> {
            small_bask: SegQueue::new(),
        }
    }
}

impl<T: Allocate> BytePool<T> {
    pub fn new() -> Self {
        BytePool::default()
    }

    pub fn alloc(&self) -> ByteBuffer<'_, T> {
        let list = &self.small_bask;
        if let Some(el) = list.pop() {
            return ByteBuffer::new(el, self);
        }

        let data = T::alloc();
        ByteBuffer::new(data, self)
    }

    fn push_raw_block(&self, buffer: T) {
        self.small_bask.push(buffer);
    }
}

impl<'a, T: Allocate> Drop for ByteBuffer<'a, T> {
    fn drop(&mut self) {
        let data = mem::ManuallyDrop::into_inner(unsafe { ptr::read(&self.data) });
        self.pool.push_raw_block(data);
    }
}

impl<'a, T: Allocate> ByteBuffer<'a, T> {
    fn new(data: T, pool: &'a BytePool<T>) -> Self {
        ByteBuffer {
            data: mem::ManuallyDrop::new(data),
            pool,
        }
    }

    pub fn size(&self) -> usize {
        std::mem::size_of::<T>()
    }
}

impl<'a, T: Allocate> Deref for ByteBuffer<'a, T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &Self::Target {
        self.data.deref()
    }
}

impl<'a, T: Allocate> DerefMut for ByteBuffer<'a, T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.data.deref_mut()
    }
}

unsafe impl<'a, T: StableDeref + Allocate> StableDeref for ByteBuffer<'a, T> {}

fn main() {
    let p = BytePool::<Header>::new();
    {
        let mut t = p.alloc();
        t.a = 1;
        println!("{:#}", t);
    }

    let mut t = p.alloc();
    t.a = 1;
    println!("{:#}", t);
}

相关文章

  • Rust手动管理内存

    为了确保安全性,Rust在零抽象的基础上,限制了很多易导致潜在bug的操作,比如直接指针操作,以及长生命周期等等,...

  • Rust 语言

    Rust 安全高效的语言 安全: 开发人员无需手动管理内存。 高效: 开发出的软件运行效率高。rust 官网 ht...

  • 2022-07-23

    Rust Box堆分配Box 背后是调用 jemalloc 来做内存管理,所以堆上的空间无需我们的手动管理。与此类...

  • Rust核心设计之Ownership

    Ownership in Rust 背景 目前主流编程语言管理内存的方式不外乎两种--gc或者手动. owner...

  • 11-AutoreleasePool实现原理上

    我们都知道iOS的内存管理分为手动内存管理(MRC)和自动内存管理(ARC),但是不管是手动内存管理还是自动内存管...

  • 《Effective Objective-C 2.0》读书笔记(

    第五章 内存管理 第29条:理解引用计数 OC 中有手动内存管理(MRC) 自动内存管理(ARC)手动内存管理需要...

  • iOS 内存管理底层探究

    内存管理方式: MRC:手动管理内存,需要开发人员管理内存,手动调用Release,以控制对象内存的释放。ARC:...

  • ARC MRC

    内存的手动管理(MRC):手动引用计数器管理,申请到某一块内存,在使用之后,要手动释放;未释放内存,会造成内存的浪...

  • rust 内存管理

    1、&变量 => 不可变取地址 1. 传递内存地址 2. 传递数组 3. 无法通过地址修改内存数据 2、&mut ...

  • iOS 内存管理

    一、Manual Reference Counting「手动引用计数」手动内存管理 1. 内存管理的重要性 移动设...

网友评论

      本文标题:Rust手动管理内存

      本文链接:https://www.haomeiwen.com/subject/httnwltx.html