Rust的Vec优化


本篇是对Rust编程语言17_Rust的Vec优化[1]学习与记录

alt

MiniVec


https://crates.io/crates/minivec


enum DataWithVec {
    // tag,uint64,8字节
    I32(i32),       //  4字节,但需内存对齐到8字节?
    F64(f64),       // 8字节
    Bytes(Vec<u8>), // 24字节
}

fn main() {
    println!(
        "DataWithVec这个Option类型占的内存空间为:{}字节",
        std::mem::size_of::<DataWithVec>()
    );
}

DataWithVec这个Option类型占的内存空间为:32字节


enum占用的栈内存大小=8+其中占内存最大的字段的内存

但当100个enum类型的数据中,有80%都是8字节数据,如f64,剩下的20%才是24字节的Vec,那占得比例:


enum DataWithVec {
    // tag,uint64,8字节
    I32(i32),       //  4字节,但需内存对齐到8字节?
    F64(f64),       // 8字节
    Bytes(Vec<u8>), // 24字节
// 32 byte

enum DataWithWithoutVec {
    // tag,uint64,8字节
    I32(i32), //  4字节,但需内存对齐到8字节?
    F64(f64), // 8字节
//16 byte

fn main() {
    println!(
        "DataWithVec这个Option类型占的内存空间为:{}字节",
        std::mem::size_of::<DataWithVec>()
    );

    let ratio = (80 * std::mem::size_of::<DataWithWithoutVec>()) as f64
        / (100 * std::mem::size_of::<DataWithVec>()) as f64;

    println!("ratio:{}", ratio)
}

DataWithVec这个Option类型占的内存空间为:32字节
ratio:0.4

利用率只有40%

剩下60%的都被浪费掉了



怎样可以缩减其大小?

最直接的想法是 用指针

pub enum DataWithBoxVec {
     // tag,uint64,8字节
    I32(i32),       //  4字节,但需内存对齐到8字节?
    F64(f64),       // 8字节
    Bytes(Box<Vec<u8>>), // 8字节
}// 16 byte

但这样会有性能问题

因为使用了二级指针(因为Vec里面也有一个指向data的指针),极有可能导致缓存命中率下降.需要再从内存中把数据取到缓存中

一次缓存缺失,会比缓存命中慢一个数量级

所以尽量不用二级指针


可以变成一级指针:

struct MiniVec<T> {
    // len,capacity,T
    data: * mut(usize,usize,T)
//类似C语言的柔性数组
struct MiniVec {
    // len,capacity,T
    data: * mut(usize,usize,u8)
}


impl MiniVec  {
    pub fn new()-> MiniVec {
        MiniVec { 
            data: // 8+8+一定数量的T
     }
    }
}

也可以用实现更具体更优的第三方库 minivec[2]


MiniVec大小就是8byte了

DataWithMiniVec就是16 byte了,比之前的32 byte减少了一倍

struct MiniVec<T> {
    // len,capacity,T
    data: * mut(usize,usize,T)
}


enum DataWithMiniVec {
    I32(i32),       
    F64(f64),      
    Bytes(MiniVec<u8>), 
}


smallvec


https://crates.io/crates/smallvec


new的时候不会分配内存

fn main() {
    let vec: Vec<u8> = Vec::new();

    assert_eq!(vec.capacity(), 0)
}

分配一次堆内存很昂贵,尽可能在栈上分配

当数量较少时,在栈上操作;元素数量较多时,才在堆上分配.比较有名的第三方库 smallVec

元素大小必须在编译期就确定,是个常数

有个阈值N.当元素数量小于N,则用栈内存.(上限 一般是几K到几M) 反之元素数量很多时,就要在堆上分配



Rust中的 MaybeUninit的作用及注意点

在 Rust 中,MaybeUninit<T> 是一个非常有用但需要谨慎使用的类型,它用于处理可能未初始化的内存。它是 Rust 标准库 std::mem 模块的一部分,提供了一种处理未初始化数据的安全方式。


MaybeUninit<T> 的主要用途是处理以下场景:

  1. 延迟初始化:当你有一个类型 T,但你不想或无法立即初始化它时,可以使用 MaybeUninit<T>。这对于性能优化特别有用,尤其是在处理大型数组或复杂类型时。

  2. 避免不必要的初始化开销:对于某些类型,其默认初始化可能是昂贵的(例如,大型数组的零初始化)。使用 MaybeUninit<T> 可以避免这种开销。

  3. 与 FFI 交互:当与 C 语言接口进行交互时,你可能需要处理未初始化的内存或者由 C 代码初始化的内存。MaybeUninit<T> 在这种情况下非常有用。


注意点

使用 MaybeUninit<T> 需要特别小心,因为不当的使用可能会导致未定义行为(UB),包括内存泄漏和数据损坏。以下是一些重要的注意事项:

  1. 安全性:访问 MaybeUninit<T> 的值之前必须确保它已被正确初始化。未初始化的内存访问是未定义行为。

  2. 初始化:你必须确保在使用 MaybeUninit<T> 的值之前,它已被完全且正确地初始化。

  3. DropMaybeUninit<T> 本身不会自动调用其内部值的 drop 方法。如果 T 需要被适当地销毁,你需要手动调用 drop

  4. 内存泄漏:如果你在 MaybeUninit<T> 中存储了需要手动管理的资源(例如,指向堆内存的指针),请确保适当地释放这些资源。


示例

下面是一个简单的示例,演示了 MaybeUninit<T> 的基本使用:

use std::mem::MaybeUninit;

fn main() {
    // 创建一个未初始化的实例
    let mut uninit_array: MaybeUninit<[u325]> = MaybeUninit::uninit();

    // 安全地初始化数据
    let init_array = unsafe {
        let init_array = uninit_array.as_mut_ptr();
        for i in 0..5 {
            // 初始化数组的每个元素
            (*init_array)[i] = i as u32;
        }
        uninit_array.assume_init()
    };

    // 使用初始化后的数据
    println!("{:?}", init_array);
}

在这个例子中,创建了一个可能未初始化的数组,并在确保安全的情况下初始化它。请注意,使用 unsafe 块是必须的,因为我们在操作原始指针,并且假设初始化是安全的。不过,确保这种安全是开发者的责任。不恰当的使用 unsafe 可能会导致严重的错误。


bitVec


https://crates.io/crates/bitvec


bitVec 一般是用来存储bool类型的

一个bit就可以标识是true还是false

struct BitVec {
    bits: Vec<u64>
}

VecOption


https://crates.io/crates/vec-option


该优化可有可无


struct VecOption<T> {
    data: Vec<MaybeUninit<T>>,
    flag:BitVec,
}

当为Some时,像flag push一个true

使用时,先访问flag.

比如访问索引为3的,先看看flag[3]是true还是false,根据其值得出是Some还是None


参考资料

[1]

Rust编程语言17_Rust的Vec优化: https://www.bilibili.com/video/BV1pv4y12725

[2]

minivec: https://crates.io/crates/minivec

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/186611.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浅聊代理(应用部署)

以前很少接触过项目的上线部署&#xff0c; 我对前后端交互的认知还停留在前端一个请求 对应后端一个API 比如后端提供: /api/backend/categories -GET 前端则通过使用ajax或者axios组件去构建http请求&#xff0c; 发送到: https://host:port/api/backend/categories -GET 一、…

安全高效的PostgreSQL数据库迁移解决方案

PostgreSQL数据库是一款高度可扩展的开源数据库系统&#xff0c;支持复杂的查询、事务完整性和多种数据类型&#xff0c;这使得它成为企业中处理大规模和多样化数据需求的理想选择。在很多企业中&#xff0c;PostgreSQL不仅处理大量的交易数据&#xff0c;还支持复杂的数据分析…

Django二转Day03 04

0 cbv执行流程&#xff0c;self问题 path(index/, Myview.as_view()),Myview.as_view() 实例化后返回 变成return Myview.dispatch(request, *args, **kwargs)但是视图函数Myview中没有 dispatch 方法 所以去 父类View中寻找return View.dispatch(request, *args, **kwargs)调用…

Selenium(12):层级定位_通过父元素找到子元素

层级定位 在实际的项目测试中&#xff0c;经常会遇到无法直接定位到需要选取的元素&#xff0c;但是其父元素比较容易定位&#xff0c;通过定位父元素再遍历其子元素选择需要的目标元素&#xff0c;或者需要定位某个元素下所有的子元素。 层级定位的思想是先定位父对象&#xf…

【腾讯云云上实验室】向量数据库+LangChain+LLM搭建智慧辅导系统实践

目录 一、搭建智慧辅导系统——向量数据库实践指南1.1、创建向量数据库并新建集合1.2、使用 TKE 快速部署 ChatGLM1.3、部署 LangChain PyPDFVectorDB等组件1.4、配置知识库语料1.5、基于 VectorDB LLM 的智能辅导助手 二、LLM时代的次世代引擎——向量数据库2.1、向量数据库L…

FastDFS+Nginx - 本地搭建文件服务器同时实现在外远程访问「内网穿透」

文章目录 前言1. 本地搭建FastDFS文件系统1.1 环境安装1.2 安装libfastcommon1.3 安装FastDFS1.4 配置Tracker1.5 配置Storage1.6 测试上传下载1.7 与Nginx整合1.8 安装Nginx1.9 配置Nginx 2. 局域网测试访问FastDFS3. 安装cpolar内网穿透4. 配置公网访问地址5. 固定公网地址5.…

ProgrammingError: nan can not be used with MySQL

该错误怎么发生的&#xff1f; 我们先在本地创建测试表&#xff1a; CREATE TABLE users_test (id int NOT NULL AUTO_INCREMENT COMMENT 主键,trade_account varchar(50) DEFAULT NULL COMMENT 交易账号,username varchar(50) DEFAULT NULL,email varchar(100) DEFAULT NULL…

数字系列——数字经济

数字经济是全球经济未来发展方向&#xff0c;正在成为重组全球要素资源、重塑全球经济结构、改变全球竞争格局的关键力量。都知道数字经确实很重要&#xff0c;但有些人还傻傻搞不懂数字经济到底是什么&#xff1f;小编今天就给大家捋一捋。 什么是数字经济&#xff1f; 数字经…

Glove学习笔记

global vectors for word representation B站学习视频 1、LSA与word2vec 我们用我们的见解&#xff0c;构建一个新的模型&#xff0c;Glove&#xff0c;全局向量的词表示&#xff0c;因为这个模型捕捉到全局预料的统计信息。 LSA:全局矩阵分解word2vec&#xff1a;局部上下文…

AI生成的图片有版权了

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 把发到小红书的AI图片搬运到百家号&#xff0c;然后被起诉了! 长知识了&#xff0c;原来AI生成的图片也有版权了&#xff0c;AI生成图片著作权第一案判了&#xff0c;这绝对是一件划时代事情&…

微信小程序真机调试技巧,解决各种疑难杂症

1.在真机上看log 也许你调试的时候&#xff0c;会使用到真机调试或者预览模式或者体验版模式&#xff0c;这些模式都有可能出现意想不到的bug问题&#xff0c;这时候调试模式就非常非常重要了&#xff0c;特别是给领导看的时候&#xff0c;在领导手机上出现bug了&#xff0c;这…

QT 项目中添加文件夹(分类文件)

为了更方便的整理项目的文件&#xff0c;添加文件夹把文件进行分类。 1.首先在项目文件中创建新的文件夹 2.把需要归类的文件放入新建的文件中 3.右键然后选择add..... 4.运行此程序&#xff0c;会报错因为文件路径改变了&#xff0c;需要在.pro中修改路径 注意事项 文件夹内部…

NSSCTF第14页(2)

[UUCTF 2022 新生赛]ezpop 提示说看看反序列化字符串逃逸 PHP反序列化字符串逃逸_php反序列化逃逸-CSDN博客 php反序列化字符逃逸_php反序列化逃逸_Leekos的博客-CSDN博客 buuctf刷题9 (反序列化逃逸&shtml-SSI远程命令执行&idna与utf-8编码漏洞)_extract($_post);…

码云配置遇到秘钥不正确

你这个就是秘钥没有和git绑定&#xff0c; 需要 git config --global user.name "你的用户名随便写" git config --global user.email "你的邮箱"

DCAMnet网络复现与讲解

距论文阅读完毕已经过了整整一周多。。。终于抽出时间来写这篇辣&#xff01;~ 论文阅读笔记放这里&#xff1a; 基于可变形卷积和注意力机制的带钢表面缺陷快速检测网络DCAM-Net&#xff08;论文阅读笔记&#xff09;-CSDN博客 为了方便观看&#xff0c;我把结构图也拿过来了。…

软考:2024年软考高级:软件工程

软考&#xff1a;2024年软考高级: 提示&#xff1a;系列被面试官问的问题&#xff0c;我自己当时不会&#xff0c;所以下来自己复盘一下&#xff0c;认真学习和总结&#xff0c;以应对未来更多的可能性 关于互联网大厂的笔试面试&#xff0c;都是需要细心准备的 &#xff08;1…

2023 年 IntelliJ IDEA下载、安装教程,附详细图文

大家好&#xff0c;今天为大家带来的是 2023年 IntelliJ IDEA 下载、安装教程&#xff0c;超详细的图文教程&#xff0c;亲测可用。 文章目录 1 IDEA 下载2 IDEA 安装3 IDEA 使用4 快捷键新手必须掌握&#xff1a;Ctrl&#xff1a;Alt&#xff1a;Shift&#xff1a;Ctrl Alt&a…

机械臂仿真之vrep如添加视觉传感器

基于视觉的机械臂作业任务&#xff0c;如何在vrep中加入视觉传感器&#xff0c;并获取画面&#xff1f;

认证鉴权方案

现在一般使用比较多的认证方式有四种: SessionTokenSSO单点登录OAtuth登录1.Cookie + Session 最常见的就是 Cookie + Session 认证。 Session,是一种有状态的会话管理机制,其目的就是为了解决HTTP无状态请求带来的问题。 当用户登录认证请求通过时,服务端会将用户的信息存…

【排序,直接插入排序 折半插入排序 希尔插入排序】

文章目录 排序排序方法的分类插入排序直接插入排序折半插入排序希尔插入排序 排序 将一组杂乱无章的数据按照一定规律排列起来。将无序序列排成一个有序序列。 排序方法的分类 储存介质&#xff1a; 内部排序&#xff1a;数据量不大&#xff0c;数据在内存&#xff0c;无需…