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 多平台发布

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

免费SSL证书有效果吗?

首先&#xff0c;我们要明确一点&#xff1a;无论是付费还是免费的SSL证书&#xff0c;它们都能实现基本的HTTPS加密功能&#xff0c;确保数据在客户端和服务器之间的传输过程中不会被窃取或篡改。从这个角度来看&#xff0c;免费SSL证书的确可以提供一定的安全保障。 然而&…

3D点云目标检测:VoxelNex解读

VoxelNext 通用检测器 vs VoxelNext一、3D稀疏卷积模块1.1、额外的两次下采样消融实验结果代码 1.2、稀疏体素删减消融实验&#xff1a;代码 二、稀疏体素高度压缩代码 三、稀疏预测head 通用检测器 vs VoxelNext 一、3D稀疏卷积模块 1.1、额外的两次下采样 使用通用的3D spa…

免费版的水淼采集器下载-水淼采集器详细使用教程

在当今信息爆炸的时代&#xff0c;网络上的数据量庞大&#xff0c;如何高效地采集、整理并利用这些信息成为了许多人关注的问题。水淼采集器作为一种强大的免费工具&#xff0c;在信息搜集的领域扮演着举足轻重的角色。本文将深入探讨水淼采集器的使用以及提供一份简明易懂的教…

dapper+mysql查询报Error parsing column 0 (Id=<null>)

之前的分页接口都是正常的&#xff0c;突然就报错了Error parsing column 0 (Id<null>) {"error": {"code": null,"message": "Error parsing column 0 (Id<null>)","details": "DataException: Error pa…

centos7安装mysql 8.0.31报错Failed to find valid data directory.

报错信息如下&#xff1a; 根据其他博客提示&#xff0c;执行了以下命令&#xff1a; mysqld --initialize --console 日志有新的报错&#xff1a;The designated data directory /var/lib/mysql/ is unusable. Y ou can remove all files that the server added to it. 根据…

【JAVA面向对象编程】--- 探索子类如何继承父类

&#x1f308;个人主页: Aileen_0v0&#x1f525;学习专栏: Java学习系列专栏 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 继承 继承的普通成员方法调用 及 普通成员变量修改 构造方法的调用 子类构造方法 继承 package Inherit;class Animal …

深入了解Java8新特性-日期时间API之TemporalAdjusters与TemporalAdjuster

阅读建议 嗨&#xff0c;伙计&#xff01;刷到这篇文章咱们就是有缘人&#xff0c;在阅读这篇文章前我有一些建议&#xff1a; 本篇文章大概10000多字&#xff0c;预计阅读时间长需要10分钟。本篇文章的实战性、理论性较强&#xff0c;是一篇质量分数较高的技术干货文章&…

网站提示不安全?

随着互联网的普及和发展&#xff0c;网络安全问题日益严重。黑客攻击、数据泄露、恶意软件等问题层出不穷&#xff0c;给企业和个人带来了巨大的损失。在这个背景下&#xff0c;确保网站安全显得尤为重要&#xff0c;而使用SSL证书是解决这些问题的有效措施。 什么是SSL证书&am…

C++调用python: VS2017 + Anaconda + pypi第三方库

步骤一&#xff1a;在Anaconda中创建虚拟环境 这一点对大家来说应该很简单&#xff0c;简单介绍一下&#xff0c;不做过多解释。值得注意的是&#xff0c;要用conda命令创建环境&#xff0c;用pip install配置环境。 conda create -n c_python_env python3.9 # 用conda创建pyt…

有IP没有域名可以申请证书吗?

一、IP证书是什么&#xff1f; ip证书是用于公网ip地址的SSL证书&#xff0c;与我们通常所讲的SSL证书并无本质上的区别&#xff0c;但由于SSL证书通常颁发给域名&#xff0c;而组织机构需要公共ip地址的SSL证书&#xff0c;这类SSL证书就是我们所说的ip证书。ip证书具有安全、…

数据结构与算法编程题35

用按层次顺序遍历二叉树的方法&#xff0c;统计树中具有度为1的结点数目。 #define _CRT_SECURE_NO_WARNINGS#include <iostream> using namespace std;typedef char ElemType; #define ERROR 0 #define OK 1 #define Maxsize 100 #define STR_SIZE 1024typedef struct B…

软件集成指南

软件集成方法&#xff1a; 1、一次性集成方式 2、增殖式集成方式 2.1、自顶向下的集成方式 2.2、自底向上的集成方式 2.3、混合集成方式

2的幂运算

2的幂 描述 : 给你一个整数 n&#xff0c;请你判断该整数是否是 2 的幂次方。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 如果存在一个整数 x 使得 n 2x &#xff0c;则认为 n 是 2 的幂次方。 题目 : LeetCode 231.2的幂 : 231. 2 的幂 分…

jmeter负载测试如何找到最大并发用户数

在性能测试中&#xff0c;当我们接到项目任务时&#xff0c;很多时候我们是不知道待测接口能支持多少并发用户数的。此时&#xff0c;需要我们先做负载测试&#xff0c;通过逐步加压&#xff0c;来找到最大并发用户数。那么当我们找到一个区间&#xff0c;怎么找到具体的值呢&a…

Large Language Models areVisual Reasoning Coordinators

目录 一、论文速读 1.1 摘要 1.2 论文概要总结 二、论文精度 2.1 论文试图解决什么问题&#xff1f; 2.2 论文中提到的解决方案之关键是什么&#xff1f; 2.3 用于定量评估的数据集是什么&#xff1f;代码有没有开源&#xff1f; 2.4 这篇论文到底有什么贡献&#xff1…

Python-简单模拟斗地主洗牌发牌

额滴名片儿 &#x1f388; 博主&#xff1a;一只程序猿子 &#x1f388; 博客主页&#xff1a;一只程序猿子 博客主页 &#x1f388; 个人介绍&#xff1a;爱好(bushi)编程&#xff01; &#x1f388; 创作不易&#xff1a;如喜欢麻烦您点个&#x1f44d;或者点个⭐&#xff01…

组合(回溯算法)

77. 组合 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 样例输入 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [[2,4],[3,4],[2,3],…

Linux基本指令(中篇)

目录 8.cp指令&#xff08;重要&#xff09; 9.mv指令&#xff08;重要&#xff09;&#xff1a; 10.cat指令&#xff08;适合查看小文件内容&#xff09; 11.more指令&#xff08;适合查看大文件内容&#xff09; 12.less指令&#xff08;重要&#xff09; 13.head指令和…

开源众筹平台系统源码/高仿某滴筹平台源码/PHP源码/互助众筹系统网站源码

源码简介&#xff1a; 开源众筹平台系统源码&#xff0c;它是高仿某滴筹平台源码&#xff0c;互助众筹系统网站源码&#xff0c;作为PHP源码&#xff0c;很实用。 高仿水滴筹源码,全开源uniappfastadmin开发 这套是uniapp 开发源码,非常人性化,可以随意二开 源码链接&#xf…

上门服务系统|东郊到家软件提供高效服务的科技支柱

预约上门服务系统的崛起改变了传统服务行业的格局。用户不再需要亲自前往实体店面&#xff0c;而是通过几次点击就能享受到各类服务。这背后离不开预约上门服务系统的智能化和高效性&#xff0c;而源码正是这个系统的灵魂所在。下面小编就给大家介绍下上门服务系统开发优势。 1…