#memory-allocator #vec #dont #raw #how #handle #wrapped

vec_mem_heap

A probably bad memory allocator wrapped in Rust's Vec<> because I don't know how to handle raw memory yet

6 releases

new 0.2.0 Dec 15, 2024
0.1.4 Nov 14, 2024

#232 in Memory management

Download history 312/week @ 2024-11-08 43/week @ 2024-11-15 4/week @ 2024-11-22 11/week @ 2024-11-29 23/week @ 2024-12-06

151 downloads per month

MIT license

18KB
201 lines

vec_mem_heap

An unfinished and probably bad memory allocator and ownership sharer wrapped in Rust's Vec because I don't know how to handle raw memory yet. Documentation was done a bit hastily, expect stuff like use examples to be added as I feel like it.

There should be two major reworks before this project is considered 'complete' (unless I think of more):

  • Removing the middle man (Vec<>) and handling memory management directly.
  • Adding multiple 'buckets' to hold data of different sizes to minimize fragmentation.

These changes could come in any order, at any time, so I wouldn't rely on this unless you're me until it hits version 1.

Docs: https://docs.rs/vec_mem_heap/0.1.3/vec_mem_heap/


lib.rs:

Unoptimized virtual memory allocator.

This is a learning experience for me and should be used with a mountain of salt.

Effectively a custom implementation of std::rc with a focus on streamlining the creation of a large number of shared-ownership data and ensuring all of that data is stored (more or less) contiguously in memory. Data is stored in a [Vec] (until I learn how to handle raw memory), and [Index]es are used to read and write.

Example

use vec_mem_heap::*;

fn main() {

    let mut mem_heap : MemHeap<u32> = MemHeap::new();

    let data1 = mem_heap.push(15, false); //data1 == Index(0)
    //Normally you'd write matches here to catch AccessErrors, but that's a lot of writing I don't want to do
    _ = mem_heap.add_owner(data1);

    {
        let data2 = mem_heap.push(72, false); // data2 == Index(1)
        //Index derives copy, so it can be passed around as parameters without worrying about references/ownership.
        _ = mem_heap.add_owner(data2);

        let data3 = mem_heap.push(7, true); // data3 == Index(2)
        //The data located at data3 (Index(2)) is protected, meaning calling add_owner will result in an AccessError::ProtectedMemory, which can be caught with a match
        match mem_heap.add_owner(data3) {
            Ok(_) => {
                //Whatever
            },
            Err(AccessError:ProtectedMemory(_)) => println!("Attempted to modify protected memory"),
            Err(error) => _ = dbg!(error),
        }

        let data4 = data1;
        //The value stored in mem_heap.data(Index(0)) now has two owners.
        _ = mem_heap.add_owner(data4);
    
        //data2, data3, and data4 are about to go out of scope, so we have to manually remove them as owners.
        //Ok( Some(72) ) -> The data at Index(1) only had one owner, so it was collected
        _ = mem_heap.remove_owner(data2);
        // Err( AccessError::ProtectedMemory( Index(2) ) ) -> The data at Index(2) was protected, we can't modify its owner_count
        _ = mem_heap.remove_owner(data3); 
        // Ok( None ) -> The data at Index(0) had two owners, now has one owner. Nothing needs to be done
        _ = mem_heap.remove_owner(data4); 
    }
    // Ok( &15 ) -> The data at Index(0) still has one owner (data1). If the data didn't derive copy, we would recieve &data instead.
    _ = dbg!( mem_heap.data( Index(0) ) );
    // Err( AccessError::FreeMemory(Index(1)) ) -> The data at Index(1) was garbage collected when its final owner was removed
    _ = dbg!( mem_heap.data( Index(1) ) );

}

Dependencies

~0.3–1MB
~21K SLoC