Solidity - 內(nèi)存布局

2018-10-24 筆記


Solidity - 引用類型中提到,當(dāng)沒有給局部變量的uint[] storage p賦值的時(shí)候,p會(huì)默認(rèn)指向storage的第一個(gè)slot。
首先,slot的英文翻譯是指容器的插槽、投幣口,暫時(shí)先不解釋這個(gè)東西。先看看storage,官方對(duì)storage的解釋是

Every account has a persistent key-value store mapping 256-bit words to 256-bit words called storage.
中文意思是,storage是一個(gè)持久化的存儲(chǔ)區(qū),它將32字節(jié)的鍵映射到32字節(jié)的鍵。

簡單理解就是,storage是一個(gè)超大的數(shù)組,數(shù)組可以看成儲(chǔ)物柜,slot就是一個(gè)個(gè)的小柜子。

數(shù)組.png

其中每一個(gè)slot的大小是32字節(jié),slot0的地址(即storage的起始地址)是0x00。Solidity對(duì)聲明時(shí)候沒有進(jìn)行初始化的變量,都默認(rèn)值為0。因此p作為一個(gè)指針,其中指針的值就是內(nèi)存的地址(這點(diǎn)與C語言指針一樣),因此它會(huì)指向slot0。至于為什么a的值變了,當(dāng)然就是因?yàn)?code>a存儲(chǔ)在了slot0。
下面整理一下storage內(nèi)存布局的幾條規(guī)則:

  1. 變量位置按照聲明的順序,從slot0開始排序。因此a存儲(chǔ)在了slot0。
  2. 變量占用的內(nèi)存大小與他定義的類型一致,也就是uint256占用32個(gè)字節(jié),uint8占用1個(gè)字節(jié)。
  3. 如果一個(gè)變量不能完全存在一個(gè)slot中,那么他就從下一個(gè)slot開始存儲(chǔ)。
uint8 a;      //存儲(chǔ)在slot0
uint256 b;    //因?yàn)閟lot0剩余的空間不夠存下一個(gè)uint256,則從slot1開始存儲(chǔ),另外uint 相當(dāng)于 uint256
  1. structsarrays總是在一個(gè)新的slot中開始存儲(chǔ),并且占用整個(gè)slot,但每一個(gè)元素是緊緊相挨的。
pragma solidity ^0.4.0;
contract hello {
        struct items {
            uint8 a;
            uint8 b;
        }
        items[3] public items_arr;
}

items_arr數(shù)組有三個(gè)元素,他們的內(nèi)存占用情況是,首先struct items的內(nèi)存占用是2字節(jié),然后按照一個(gè)struct占用一個(gè)slot的話,那么items_arr占用了3*32的字節(jié),其中很多都浪費(fèi)了。(這個(gè)其實(shí)我自己也不太肯定,因?yàn)槭褂肦emix調(diào)試的時(shí)候,看不到storage內(nèi)存詳情,也許要通過指令集來判斷,這里暫時(shí)存疑,以后驗(yàn)證再補(bǔ)充。XXX)

Arrays的存儲(chǔ)方式

arrays有兩種類型,靜態(tài)長度uint[3]與動(dòng)態(tài)長度uint[]。靜態(tài)長度的話,在編譯的時(shí)候,就可以確定他的內(nèi)存占用大小,因此可以提前分配。但是動(dòng)態(tài)長度的array,他的元素大小是不確定的,因此需要使用別的方式來存儲(chǔ)動(dòng)態(tài)長度的數(shù)組。舉個(gè)例子:

pragma solidity ^0.4.0;
contract hello {
        uint a;
        uint[] public b;
        uint c;
        uint[3] d;
}

其中a的位置是slot0,那么b的位置是slot1c的位置是slot2,d的位置是slot3-slot5??梢钥吹絼?dòng)長數(shù)組只占用了一個(gè)slot,然后這個(gè)位置用來存放動(dòng)長數(shù)組的長度,即b.lenght的值。動(dòng)態(tài)數(shù)組的元素存儲(chǔ)在其他的位置,這個(gè)位置根據(jù)keccak256()方法計(jì)算出來,比如b[1]的位置就是keccak256(1 . p)。其中pb所在slot1的起始地址0x32(因?yàn)橐粋€(gè)slot32個(gè)字節(jié)),另外.代表的是連接符。

Mappings的存儲(chǔ)方式

Mappings也會(huì)占用一個(gè)slot,但是這個(gè)slot是空的,不記錄東西,用來做為尋找元素的基址,尋址方式則跟Arrays的一樣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容