国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

用了這么多年Rust終于搞明白了內(nèi)存分布!

這篇具有很好參考價值的文章主要介紹了用了這么多年Rust終于搞明白了內(nèi)存分布!。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

用了這么多年Rust終于搞明白了內(nèi)存分布!

導讀
Rust作為一門學習曲線十分陡峭的語言,掌握其核心基礎數(shù)據(jù)結(jié)構(gòu)的內(nèi)存分布對學習Rust會有很大的幫助,本文由淺入深仔細介紹了Rust的各個數(shù)據(jù)結(jié)構(gòu)在內(nèi)存中的分布情況。
Rust作為一門學習曲線十分陡峭的語言,掌握其核心基礎數(shù)據(jù)結(jié)構(gòu)的內(nèi)存分布對學習Rust會有很大的幫助,即使對于已經(jīng)熟悉Rust的同學,深入數(shù)據(jù)結(jié)構(gòu)分布也能幫助到調(diào)優(yōu)Rust程序。
接下來,我會由淺入深仔細介紹Rust的各個數(shù)據(jù)結(jié)構(gòu)在內(nèi)存中的分布情況,幫助大家學習Rust。

先決條件 Prerequisite

在開始介紹之前,我們先做這個幾個假設,來更好地幫助后續(xù)文章的展開。
  1. 我們本文的機器預設是32位的(主要為了畫圖可以精簡一點),所有和位相關的數(shù)據(jù)結(jié)構(gòu)均會用上標標記(即這些數(shù)據(jù)結(jié)構(gòu)占用的是1 machine word)。例如:

  2. 數(shù)據(jù)結(jié)構(gòu)基本單位示圖:

    用了這么多年Rust終于搞明白了內(nèi)存分布!

藍色的框框代表1個byte,綠色的框框pointer下的(1|2|3|4)代表pointer在32位機器上rust是4個byte,他們整體被框在綠色框框中代表一個pointer。

?

一、基本類型

不用害怕,讓我們把一只小腳試探性地邁入Rust的大門,先看看基礎類型的內(nèi)存分布吧。

用了這么多年Rust終于搞明白了內(nèi)存分布!

這些數(shù)據(jù)結(jié)構(gòu)Rust分配的時候都是在棧上的。

?

1.1 Stack棧 vs Heap堆

因為本文會涉及到Rust中棧和堆分配,本小章先來簡單講一下棧和堆。
我們只提煉一些最基本的區(qū)別概要,更多的細節(jié)可以看這篇文章[1]有比較好的解釋。

棧特點:

  1. 分配快
  2. 大小受限
堆特點:
  1. 分配慢
  2. 大小不受限
  3. ?

二、元組 Tuple

?

讓我們先從比較基礎的Rust數(shù)據(jù)結(jié)構(gòu)Tuple看起。

let a:(char, u8, i32) = ('a', 7, 354);
size_of::<(char, u8, i32)>(); // 打印結(jié)果 12
align_of::<(char, u8, i32)>(); // 打印結(jié)果 4
該元組由三個元素構(gòu)成——char、u8和i32,由1 基本類型中可知char占4 bytes,u8占1 byte, i32占4bytes,那么初步計算出來這個tuple占用的總內(nèi)存應為4+1+4 = 9 bytes。接著,Rust會選擇Tuple中對齊值最大的元素為a該元組的對齊值,由此上例alignment是4。有了整體對齊值,Rust會在內(nèi)存中加入一段填充(padding)來讓整體內(nèi)存占用是alignment的整數(shù)倍,本例中加在u8與i32中間是為了保障i32自身的內(nèi)存對齊。
由于Rust有多種數(shù)據(jù)排布風格(默認的Rust風格,還有C語言風格,primitive和transparent風格),在Rust風格中,Rust可以對元組中的元素做任意重排,也包括padding的位置,因而圖中的排列只是一種可能,也許i32和char的位置在Rust中會進行互換,Rust是根據(jù)其優(yōu)化算法做出其認為最優(yōu)的排序,對最終排序結(jié)果并沒有統(tǒng)一規(guī)則。

用了這么多年Rust終于搞明白了內(nèi)存分布!

上圖為該tuple的內(nèi)存分布圖。

三、引用 Reference

引用 reference 是Rust中的一個重要概念,相關規(guī)則也是支撐了Rust內(nèi)存安全的重要支柱。我們來看下面的例子。

let a: i8 = 6;
let b : &i8 = &a;

a?是一個i8,b是一個指向?a?的reference,我們可以看下他倆的內(nèi)存分布。

用了這么多年Rust終于搞明白了內(nèi)存分布!

首先,Rust會在棧上分配一個大小為1byte的i8存儲a,接著會在內(nèi)存另外一個空間(不一定和a連續(xù))分配b,b中存儲的內(nèi)存空間會指向a所在的內(nèi)存空間,同時b的內(nèi)存占用大小即pointer的大小。

需要注意的是,&T和&mut T在內(nèi)存分布上規(guī)則一致,他們的區(qū)別是在使用方式和編譯器處理方式上。

?

四、Array數(shù)租 和 Vector動態(tài)數(shù)組

接下來我們來看看Rust的數(shù)組Array和動態(tài)數(shù)組Vector的內(nèi)存分布,以下面的數(shù)組和動態(tài)數(shù)組為例。


let a: [i8; 3] = [1, 2, 3];
let b: Vec<i8> = vec![1, 2, 3];

數(shù)組Array是固定大小的,所以在創(chuàng)建的時候都指定好了長度;動態(tài)數(shù)組Vector,由其名字就可以知道他是可以自由伸縮的,那么我們來看看Rust是怎么在內(nèi)存上存儲這兩位數(shù)據(jù)結(jié)構(gòu)的。

用了這么多年Rust終于搞明白了內(nèi)存分布!

對于Array a,由于他固定大小為3個i8,Rust即在棧上為其分配了3 * 1 byte個內(nèi)存。
對于Vector b就有點特殊啦,他會由如下三個部分組成:
  1. pointer : pointer b會指向vector b在堆上的實際數(shù)據(jù)(目前是1, 2, 3 共3 * 1 byte),

  2. cap(圖中上標32代表這個值和機器位數(shù)有關,最后復習一次哦): cap代表最多多少個T(本例中T是i8)的內(nèi)存可以在堆上讓這個動態(tài)數(shù)組使用,默認大小為創(chuàng)建時的T個數(shù),可根據(jù)使用需求自動擴容,但每次擴容時會帶來reallocate影響到性能。

  3. len (1 machine word),代表目前有多少個T(本例中T是i8)的內(nèi)存真實被該動態(tài)數(shù)組使用。

以上即可看到數(shù)組和動態(tài)數(shù)組由于在“動態(tài)”這個特點上的不同,出現(xiàn)的內(nèi)存分布差異啦。

?

4.1 Slice 數(shù)組切片

接下來,我們通過Array和Vector來看下Rust中切片的內(nèi)存分布實現(xiàn)。
假設我們想獲取到上面例子中a和b兩個Array和Vector的前兩個元素。

let slice_1: [i32] = a[0..2];
let slice_2: [i32] = b[0..2];

然而,對于[i32],Rust沒法在編譯時明確這個變量需要多少內(nèi)存,因而也沒法在棧上分配內(nèi)存,因而上例中的slice_1和slice_2實際上會編譯失敗。這樣的變量稱之為dynamically sized type,后續(xù)會講到string slice和trait object也屬于這個范疇。

因而,通常我們使用一個reference來指向一個Slice切片,讓我們看下例

let slice_1: &[i32] = &a[0..2]
let slice_2: &[i32] = &b[0..2]

當reference指向dynamically sized type時,Rust實際會使用到一個胖指針(fat pointer),其中包含:

  1. pointer (1 machine word):指向?qū)嶋H被切片的數(shù)據(jù)。

  2. length (1 machine word): 切片長度,即有多少個T(本例中T為i32)。

我們可以看下上述例子的內(nèi)存分布圖。

用了這么多年Rust終于搞明白了內(nèi)存分布!

五、String, str, &str

接下來讓我們來看下String, str 和&str的內(nèi)存分布。以一個例子開始吧。

let s1: String = String::from(“HELLO”);
let s2: &str = “ЗдP”;  // д -> Russian Language
let s3: &str = &s1[1..3];

首先,s1是一個String,String實質(zhì)上就是Vec的一個包裝,其中也是在棧上有一個指針 + cap( 1 machine word ) + len ( 1 machine word ),指針指向了該String實際在堆上的值。String是保證UTF-8兼容的。

如果我們直接在變量中存了一個字符串字面值(string literal),例如s2,那么這個變量會是一個指向string slice的指針。這個string數(shù)據(jù)不會存儲在堆heap上,而是會直接存在編譯后的二進制中,同時他們具有static生命周期,即直到程序結(jié)束前都不會被釋放。如同前面講的slice以后,&str也同樣是個胖指針,同時包含了實際數(shù)據(jù)的內(nèi)存地址和數(shù)據(jù)長度(一共2 machine words)。這里的例子里用了一個特殊字符д,由于UTF-8是一種可變長的編碼方式,這里可以看到д就用了2個byte來表達。
s3的情況與4.1中類似,使用到一個胖指針(fat pointer),其中包含:
  1. pointer (1 machine word):指向?qū)嶋H被切片的字符串。

  2. length (1 machine word): 切片長度。

用了這么多年Rust終于搞明白了內(nèi)存分布!

六、Struct

Rust有三種結(jié)構(gòu)體類型定義方式:

?

6.1 unit-like Struct

struct Data

用了這么多年Rust終于搞明白了內(nèi)存分布!

由于并沒有定義Data結(jié)構(gòu)體的細節(jié),Rust也不會為其分配任何內(nèi)存。

?

6.2 Struct with named fields && tuple-like struct

這兩種結(jié)構(gòu)體的內(nèi)存分配方式是類似的,我們來看一個例子就好。

struct Data {
   nums: Vec<usize>,
   dimension: (usize, usize),
}

用了這么多年Rust終于搞明白了內(nèi)存分布!

首先,nums是Vec,占用3個 machine word(pointer + cap + len),pointer指向heap上實際動態(tài)數(shù)組的值;dimension是兩個usize組成的tuple,占用2個machine word。由于之前談到,Rust風格的數(shù)據(jù)排布是可以做任意重排的,所以具體的padding在圖中就并沒有畫出了。

七、Enum


enum HTTPStatus {
   Ok,
   NotFound,
}

對于C-style enum,在內(nèi)存中,rust會根據(jù)該enum中最大的數(shù)來選擇內(nèi)存占用最小的int來存儲,此例中沒有指定就會默認Ok為0,NotFound為1,Rust選擇占用1 byte的i8來存儲enum。

同時,每個Enum的整數(shù)值是可以指定的,例如:

enum HttpStatus {
   Ok = 200,
  NotFound = 404,
}
本例中,Rust會選擇占用2 byte的i16來存儲enum(以滿足存儲404)。
接著我們來看更復雜一些的Enum:

 Empty,
  Number(i32),
  Array(Vec<i32>),
?
對于這類有具體數(shù)據(jù)結(jié)構(gòu)的Enum,每一個Enum中的元素都有一個 1 byte的tag,tag用于標識屬于Enum中具體哪個變量。此例中,Empty的話tag為0,而Empty后的內(nèi)存空間都是為了滿足對齊要求而構(gòu)造的padding,后續(xù)的i32和Vec均和之前介紹的分布一樣,在enum中它們有不同的幾點:加入了1 byte tag以及padding,因而也可以看到每一個Enum所占的空間由其中占用空間最大的變量所決定,如果要優(yōu)化Enum的空間占用,可以從削減其中最大元素做起。
(padding的位置是不固定的,Rust會根據(jù)具體數(shù)據(jù)結(jié)構(gòu)的內(nèi)存分布調(diào)整padding位置以做優(yōu)化)

?

7.1 Option

Rust中的Option實質(zhì)上是便是一種Enum,我們可以看下Option的定義:

pub enum Option<T> {
  None,
  Some(T),
}
Rust通過None和Some的區(qū)分,避免了其他語言中可能發(fā)生的空指針訪問問題。我們可以看下Option<Box<i32>>這個例子,稍后我們會仔細介紹Box,在這里你可以先理解Box會將原來的i32從棧放到堆,然后Box會是一個指針指向原來的i32新的堆的地址。

用了這么多年Rust終于搞明白了內(nèi)存分布!

由于pointer本身只占1 machine word,而tag的存在多了1 byte,導致Rust需要根據(jù)對齊值加入paddign使其對齊,使得整體內(nèi)存占用提升,很明顯這里有可以優(yōu)化的空間。于是,Rust對于類似Box這樣的不允許為null的SmartPointer,Rust進行了如下優(yōu)化:

用了這么多年Rust終于搞明白了內(nèi)存分布!

如此,整體內(nèi)存占用降到了1 machine word。如果該Option值為0,那么Rust就知道他是None,如果非0,那么Rust就知道他是Some,通過這樣省去了tag的作用并且節(jié)省了內(nèi)存空間消耗。

八、Box

對于通常默認分配在棧上的變量,使用 Box 可以將其分配到堆上,??臻g上只用分配指向堆數(shù)據(jù)的指針。
我們以一個tuple為例let t: (i32, String) = (5, “Hello”.to_string);?,在沒有經(jīng)過Box處理前,它的內(nèi)存分布如下圖:

用了這么多年Rust終于搞明白了內(nèi)存分布!


(圖中省去了padding)
如果我們將該數(shù)據(jù)結(jié)構(gòu)放到Box b中,即

let t: (i32, String) = (5, “Hello”.to_string);
let mut b = Box::new(t);
內(nèi)存分布則如下圖:

用了這么多年Rust終于搞明白了內(nèi)存分布!

可以看到,原本在棧上的內(nèi)容都被轉(zhuǎn)移到Heap上,減少了我們在棧上的內(nèi)存空間消耗。文章來源地址http://www.zghlxwxcb.cn/news/detail-433120.html

基礎篇在這里就完結(jié)啦,后續(xù)會繼續(xù)展開進階篇,對Rust的Copy&Move, 智能指針, Arc等特性做進一步展開。
參考鏈接:
[1]https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/the-stack-and-the-heap.html
作者|吳超(律霜)

到了這里,關于用了這么多年Rust終于搞明白了內(nèi)存分布!的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 干了這么多年C#,后悔沒早點用這種“分頁”,簡單/高效/易維護

    干了這么多年C#,后悔沒早點用這種“分頁”,簡單/高效/易維護

    【前言】 干了這么多年C#,后悔沒早點用這種“分頁”,簡單/高效/易維護,比其它的分頁方式強多了,不信你自己看。 ? 【正文】 支持.Net Core(2.0及以上)與.Net Framework(4.5及以上) 可以部署在Docker, Windows, Linux, Mac。 ? 從NuGet引入DeveloperSharp包,然后像如下那樣使用分頁功能:

    2024年02月13日
    瀏覽(21)
  • 終于有人把大數(shù)定律講明白了

    終于有人把大數(shù)定律講明白了

    導讀: 在一些情況下,概率是由頻率推導而來的,要得到可信的概率,就要大量重復地試驗。而且,重復試驗的次數(shù)越多,結(jié)論就越讓人信服。那么,為何人們直覺上更愿意相信從大數(shù)據(jù)中得到的統(tǒng)計結(jié)果,而不是從小數(shù)據(jù)中得到的經(jīng)驗呢? 作者:徐晟 來源:大數(shù)據(jù)DT(I

    2023年04月14日
    瀏覽(30)
  • 云計算發(fā)展的 4 個階段,終于有人講明白了

    云計算發(fā)展的 4 個階段,終于有人講明白了

    導讀: 云計算從誕生至今,經(jīng)歷了四個發(fā)展階段,目前仍然在高速演進中。 作者:阿里云智能-全球技術(shù)服務部 來源:大數(shù)據(jù)DT(ID:hzdashuju) 01 公有云 公有云是云計算最早期的形態(tài),也是截至目前眾多云廠商期望實現(xiàn)的終極形態(tài),它是從彈性計算共享資源租用服務開始的。

    2024年02月06日
    瀏覽(26)
  • 什么是目標檢測?有哪些應用?終于有人講明白了

    什么是目標檢測?有哪些應用?終于有人講明白了

    導讀: 計算機視覺(Computer Vision,CV)是一門教計算機如何“看”世界的學科。計算機視覺包含多個分支,其中圖像分類、目標檢測、圖像分割、目標跟蹤等是計算機視覺領域最重要的研究課題。本文將著重介紹目標檢測的相關知識,并提供一些實例,以幫助讀者對目標檢測

    2023年04月24日
    瀏覽(26)
  • 用了這么久rabbitmq,你還不知道它的目錄結(jié)構(gòu)嗎?

    用了這么久rabbitmq,你還不知道它的目錄結(jié)構(gòu)嗎?

    rabbitmq配置目錄:/etc/rabbitmq/ ? 常見配置文件有: (1)配置文件 rabbitmq.conf (2)環(huán)境變量文件 rabbitmq-env.conf (3)補充配置文件 advanced.config rabbitmq數(shù)據(jù)目錄:/var/lib/rabbitmq/ 目錄文件有: rabbitmq日志文件: /var/log/rabbitmq ? 目錄文件有: rabbitmq命令腳本:/usr/lib/rabbitmq/ 1.bin目錄

    2024年02月16日
    瀏覽(103)
  • Spring使用三級緩存解決循環(huán)依賴?終于完全弄明白了

    文章閱讀前推薦 推薦先去看看源碼,源碼很短,但是對于我們在腦子里構(gòu)建一個完整思路很重要。看起來非常簡單,只需要雙擊shift,全局查找文件:AbstractAutowireCapableBeanFactory,找到550行左右的doCreateBean方法,重點看一下580行到600行這20行代碼就行,包含了三級緩存、屬性注

    2024年03月25日
    瀏覽(31)
  • 終于有人把騰訊云輕量服務器“月流量”說明白了

    終于有人把騰訊云輕量服務器“月流量”說明白了

    騰訊云輕量服務器月流量什么意思? 月流量是指輕量服務器限制每月流量的意思,不能肆無忌憚地使用公網(wǎng),流量超額需要另外支付流量費,上海/廣州/北京等地域的輕量服務器月流量不夠用超額部分按照0.8元/GB的價格支付流量費 。阿騰云atengyun.com來詳細說下騰訊云輕量應用

    2024年02月07日
    瀏覽(22)
  • 云計算與數(shù)字化轉(zhuǎn)型的關系,終于有人講明白了

    云計算與數(shù)字化轉(zhuǎn)型的關系,終于有人講明白了

    導讀: 云計算與數(shù)字化轉(zhuǎn)型是相輔相成的關系。 作者:阿里云智能-全球技術(shù)服務部 來源:大數(shù)據(jù)DT(ID:hzdashuju) 01 云計算帶來的重大變化 通過數(shù)據(jù)提升效率、降低成本、進行業(yè)務創(chuàng)新,這個想法不是第一天出現(xiàn),在大型機、小型機時代就已經(jīng)出現(xiàn)了這種觀點。那個時候,

    2024年01月25日
    瀏覽(25)
  • 什么是AB實驗?能解決什么問題?終于有人講明白了

    什么是AB實驗?能解決什么問題?終于有人講明白了

    導讀: 走向身邊的AB實驗。 作者:木羊同學 來源:大數(shù)據(jù)DT(ID:hzdashuju) “AB實驗”是一個從統(tǒng)計學中借來的工具。我和大家一樣,每次只要看到“統(tǒng)計學”這三個字,下意識就覺得這事和我沒啥關系,然后手就忍不住想要點擊下一條文章。不過且慢,開篇我說AB實驗是一

    2024年02月10日
    瀏覽(26)
  • vue開發(fā)者vite多環(huán)境配置,終于搞明白了

    vue開發(fā)者vite多環(huán)境配置,終于搞明白了

    在看項目的過程中,發(fā)現(xiàn)有類似服務端多環(huán)境配置的配置,所以研究了下,在網(wǎng)上有多個方案,選了一個當前在用的吧,另外一個沒驗證 對于使用Vite構(gòu)建的Vue項目,可以使用Vite提供的環(huán)境變量來實現(xiàn)多環(huán)境配置。 Vite 使用? dotenv ?從? 環(huán)境文件目錄 ?中加載環(huán)境文件,默認

    2024年02月06日
    瀏覽(16)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包