Protobuf底層儲存原理

2022-02-04 02:37:51 字數 2817 閱讀 9122

參考官網, 序列化原理

message test1

並設定為a=150,序列化到乙個檔案中,檢視檔案,得到下面的二進位制:

08 96 01

從底層儲存的二進位制值看出,protobuf為什麼這麼快,節省記憶體了吧。

有以上的結果是因為 varints 這個特殊的東東。它可以讓已個int資料型別的儲存根據值的大小而自動改變儲存的位元組數。

varint 中的每個位元組,除了最後乙個位元組,都有最重要的位集——這表示還會有更多的位元組。每個位元組的低7位用於儲存以7位為一組的數字的兩個補碼表示形式,最先儲存的是最低位元組。

比如儲存數字1,請看二進位制格式:

0000 0001

因為只有乙個位元組,所以最高位是0.

比如儲存數字300,請看二進位制格式:

1010 1100 0000 0010

計算方法:

protobuf 的快,小就是通過以上來實現的了。。。。。。

protobuf 是一系列鍵值對。訊息的二進位制版本只使用欄位的標籤作為,每個欄位的名稱和宣告型別只能在解碼結束時通過引用訊息型別的定義來確定。

當對訊息進行編碼時,鍵和值被連線到乙個位元組流中。當訊息被解碼時,解析器能夠跳過它不認識的字段。通過這種方式,可以使舊**(相對protobuf訊息定義的新舊)能夠相容新的字段而不用修改**。為此,行格式訊息中每對的「鍵」實際上是兩個值——.proto檔案中的字段號+乙個線型別,通過該型別可以推斷出資料長度。在大多數語言實現中,這個鍵被稱為標記。

資料型別:

| type | meaning | used for |

| --- | --- | --- | --- |

| 0 | varint | int32, int64, uint32, uint64, sint32, sint64, bool, enum|

| 1 | 64-bit | fixed64, sfixed64, double|

| 2 | length-delimited | string, bytes, embedded messages, packed repeated fields|

| 3 | start group | groups (deprecated)|

| 4 | end group | groups (deprecated)|

| 5 | 32-bit | fixed32, sfixed32, float|

流訊息中的每個鍵都是乙個varint,其值為(field_number << 3) | wire_type,也就是說,數字的最後三位儲存了儲存資料報的型別。

例如:底層儲存二進位制是:

000 1000

那麼原字段的型別就是根據(field_number << 3) | wire_type得到低三位得到wire( 0 ),是乙個varint 型別,也就是數字。剩下的幾位右移,得到的是1,因此字段標籤是1

所以字段原型應該是:

struct message ;

再來看下兩個位元組的150:

由此看見,多位元組的二進位制儲存,就是多了丟棄最後一位翻轉位元組的步驟。

有符號整型(signed integers)

在protobuf中,有符號的編碼是利用了zigzag編碼,把有符號型別編碼成乙個比較大的無符號整型,提高了儲存空間和提高序列化速度。

zigzag編碼是一種應用於大量使用小整型的場景的編碼演算法,可以提高編碼速度。

非varint數字(non-varint numbers)

型別1,型別5的數字是按照小端序列來儲存的。

strings

型別為2(以長度分隔)意味著該值是varint編碼的長度,後跟指定的資料位元組數。

看這個例子:

message test2
在應用程式裡設定 b 值為testing,序列化後得到下面的二進位制串:

12 0774 65 73 74 69 6e 67

加粗的位元組是「testing」的utf8。這裡的鍵是0x12→欄位號= 2,型別= 2。值中的varint長度是7,你看,我們在它後面找到了7個位元組——我們的字串。

嵌入型別(embedded messages)
message test1 

message test3

設定test1的 a 為150,得到序列化十六進製制值:

1a 0308 96 01

最後三個位元組與上面的第乙個示例單獨test1並賦值150 (08 96 01)完全相同,它們的前面是數字3,嵌入式訊息的處理方式與字串完全相同(wire type = 2)。

Protobuf序列化的原理 負數的儲存

在計算機中,負數會被表示為很大的整數,因為計算機定義負數符號位為數字的最高位,所以如果採用varint編碼表示乙個負數,那麼一定需要5個位元位。所以在protobuf中通過sint32 sint64型別來表示負數,負數的處理形式是先採用zigzag編碼 把符號數轉化為無符號數 在採用 varint編...

HashMap底層(1 7和1 8)的儲存原理

首先說一下jdk1.7版本的存放原理 當例項化後,底層會直接建立乙個長度為16的一維陣列entry table 然後,說一下新增元素時,呼叫put方法 三種情況儲存 方式一 底層根據key計算hash值,計算出索引位置,檢視當前位置是否有值,如果沒有值,直接存放。情況二 當計算出的索引位置,有值時 ...

protobuf序列化儲存

之前做的乙個專案,為了提速,用到了序列化儲存。下面是乙個protobuf的使用示例。include person.pb.h include iostream include fstream include time.h pragma comment lib,libprotobuf.lib pragm...