自古以來,JSON序列化就是兵家必爭之地

2022-09-19 15:21:10 字數 4124 閱讀 4809

上文講到使用ioutil.readall讀取大的response body,出現讀取body超時的問題。

stackoverflow的morganbaz的看法是:

使用iotil.readall去讀取go語言裡大的response body,是非常低效的; 另外如果response body足夠大,還有記憶體洩漏的風險。

data,err:=  iotil.readall(r)

if err != nil

json.unmarshal(data, &v)

有乙個更有效的方式來解析json資料,會用到decoder型別

err := json.newdecoder(r).decode(&v)

if err != nil

這種方式從記憶體和時間角度,不但更簡潔,而且更高效。

這裡我針對前人的思路補充兩點。

官方ioutil.readall是通過初始大小為512位元組的切片來讀取reader,我們的response body大概50m, 很明顯會頻繁觸發切片擴容,產生不必要的記憶體分配,給gc也帶來壓力。

go切片擴容的時機:需求小於256位元組,按照2倍擴容;超過256位元組,按照1.25倍擴容。

怎麼理解morganbaz所說的帶來的記憶體洩漏的風險?

記憶體洩漏是指程式已動態分配的堆記憶體由於某種原因未釋放,造成系統記憶體浪費,導致程式執行速度減慢公升職系統崩潰等嚴重後果。

ioutil.readall讀取大的body會觸發切片擴容,講道理這種做法只會帶來記憶體浪費,最終會被gc釋放,原作者為什麼會強調有記憶體洩漏的風險?

我諮詢了一些童靴,對於需要長時間執行的高併發伺服器程式,不及時釋放記憶體也可能導致最終耗盡系統所有記憶體,這是一種隱式記憶體洩漏。

morganbaz大佬提出使用標準庫encoding/json來邊讀邊反序列化,

減少記憶體分配, 加快反序列化速度。

自古以來,json序列化就是兵家必爭之地,各大語言均對序列化有不同的實現思路,效能相差較大。

下面我們使用高效能json序列化庫json-iterator與原生ioutil.readall+ json.unmarshal方式做對比。

順便也檢驗我最近實踐pprof的成果。

log.println("開始請求:" + time.now().format("2006-01-02 15:04:05.010"))

if err != nil

log.println("服務端處理結束, 準備接收response:" + time.now().format("2006-01-02 15:04:05.010"))

defer response.body.close()

var resp response

var records = make(map[string]record)

resp.data = &records

err= json.newdecoder(response.body).decode(&resp)

if err != nil

log.println("客戶端讀取+解析結束:" + time.now().format("2006-01-02 15:04:05.010"))

var result = make(map[string]*data, len(records))

for _, r := range records[expr]

}return len(result)

}# 省略了反序列化的object type

記憶體對比

--- json-iterator邊讀邊反序列化 ---

--- io.readall + json.unmarshal 反序列化

我們可以點進去看io.readall + json.unmarshal記憶體耗在**?

total:     59.59mb    59.59mb (flat, cum)   100%

626 . . func readall(r reader) (byte, error)

633 . . n, err := r.read(b[len(b):cap(b)])

634 . . b = b[:len(b)+n]

635 . . if err != nil {

636 . . if err == eof {

從上圖也可以印證io.readall  為儲存整個response.body對初始512位元組的切片不斷擴容, 產生常駐記憶體59m。

你還可以對比alloc_space 分配記憶體inuse_space常駐記憶體, 這兩者的差值可粗略理解為gc釋放的部分。

從結果看json-iterator相比io.readall + json.unmarshal分配記憶體是比較小的。

1.ioutil.readall 讀取大的response.body的風險:效能差且有記憶體洩漏的風險

2.隱式記憶體洩漏:對於高併發、長時間執行的web程式,不及時釋放記憶體最終也會導致記憶體耗盡。

3.json 序列化是兵家必爭之地, json-iterator 是相容標準encode/json api 用法的高效能序列化器

4.pprof 記憶體診斷的姿勢 & 除錯指標的意義。

json序列化 反序列化

json序列化 json的dumps方法可以將json格式資料序列為python的相關資料型別,比如str,常用於列印,另外,在序列化時,中文漢字被轉換為unicode編碼,在dumps函式中新增引數ensure ascii false可解決 dumps的indent參考可以調整顯示格式,即縮排,一...

Json序列化和反序列化

json測試 public class jsontest irun 實體序列化和反序列化 string json1 jsonhelper.serializeobject sdudent json1 student sdudent1 jsonhelper.deserializejsontoobject...

json序列化與反序列化

1.什麼是序列化與反序列化?序列化就是將記憶體中的資料結構轉換成一種中間格式儲存到硬碟或者基於到網路傳輸。反序列化就是將硬碟中或者網路中傳來的一種資料格式轉換成記憶體中資料格式。2.為什麼要有序列化和反序列化?1.可以儲存程式的執行狀態。比如遊戲中使用者在某個狀態下線,使用者遊戲的資料需要儲存,這時...