精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

搞 Go 要了解的 2 個 Header,你知道嗎?

開發 后端
在這篇文章中,我們介紹了字符串(string)和切片(slice)的兩個運行時表現,分別是 StringHeader 和 SliceHeader。

[[402665]]

本文轉載自微信公眾號「腦子進煎魚了」,作者陳煎魚。轉載本文請聯系腦子進煎魚了公眾號。

大家好,我是煎魚。

在 Go 語言中總是有一些看上去奇奇怪怪的東西,咋一眼一看感覺很熟悉,但又不理解其在 Go 代碼中的實際意義,面試官卻愛問...

今天要給大家介紹的是 SliceHeader 和 StringHeader 結構體,了解清楚他到底是什么,又有什么用,并且會在最后給大家介紹 0 拷貝轉換的內容。

一起愉快地開始吸魚之路。

SliceHeader

SliceHeader 如其名,Slice + Header,看上去很直觀,實際上是 Go Slice(切片)的運行時表現。

  1. type SliceHeader struct { 
  2.  Data uintptr 
  3.  Len  int 
  4.  Cap  int 
  • Data:指向具體的底層數組。
  • Len:代表切片的長度。
  • Cap:代表切片的容量。

既然知道了切片的運行時表現,那是不是就意味著我們可以自己造一個?

在日常程序中,可以利用標準庫 reflect 提供的 SliceHeader 結構體造一個:

  1. func main() { 
  2.   // 初始化底層數組 
  3.  s := [4]string{"腦子""進""煎魚""了"
  4.  s1 := s[0:1] 
  5.  s2 := s[:] 
  6.  
  7.   // 構造 SliceHeader 
  8.  sh1 := (*reflect.SliceHeader)(unsafe.Pointer(&s1)) 
  9.  sh2 := (*reflect.SliceHeader)(unsafe.Pointer(&s2)) 
  10.  fmt.Println(sh1.Len, sh1.Cap, sh1.Data) 
  11.  fmt.Println(sh2.Len, sh2.Cap, sh2.Data) 

你認為輸出結果是什么,這兩個新切片會指向同一個底層數組的內存地址嗎?

輸出結果:

  1. 1 4 824634330936 
  2.  
  3. 4 4 824634330936 

兩個切片的 Data 屬性所指向的底層數組是一致的,Len 屬性的值不一樣,sh1 和 sh2 分別是兩個切片。

疑問

為什么兩個新切片所指向的 Data 是同一個地址的呢?

這其實是 Go 語言本身為了減少內存占用,提高整體的性能才這么設計的。

將切片復制到任意函數的時候,對底層數組大小都不會影響。復制時只會復制切片本身(值傳遞),不會涉及底層數組。

也就是在函數間傳遞切片,其只拷貝 24 個字節(指針字段 8 個字節,長度和容量分別需要 8 個字節),效率很高。

這種設計也引出了新的問題,在平時通過 s[i:j] 所生成的新切片,兩個切片底層指向的是同一個底層數組。

假設在沒有超過容量(cap)的情況下,對第二個切片操作會影響第一個切片。

這是很多 Go 開發常會碰到的一個大 “坑”,不清楚的排查了很久的都不得而終。

StringHeader

除了 SliceHeader 外,Go 語言中還有一個典型代表,那就是字符串(string)的運行時表現。

  1. type StringHeader struct { 
  2.    Data uintptr 
  3.    Len  int 
  • Data:存放指針,其指向具體的存儲數據的內存區域。
  • Len:字符串的長度。

可得知 “Hello” 字符串的底層數據如下:

  1. var data = [...]byte{ 
  2.     'h''e''l''l''o'

底層的存儲示意圖如下:

真實演示例子如下:

  1. func main() { 
  2.  s := "腦子進煎魚了" 
  3.  s1 := "腦子進煎魚了" 
  4.  s2 := "腦子進煎魚了"[7:] 
  5.  
  6.  fmt.Printf("%d \n", (*reflect.StringHeader)(unsafe.Pointer(&s)).Data) 
  7.  fmt.Printf("%d \n", (*reflect.StringHeader)(unsafe.Pointer(&s1)).Data) 
  8.  fmt.Printf("%d \n", (*reflect.StringHeader)(unsafe.Pointer(&s2)).Data) 

你認為輸出結果是什么,變量 s 和 s1、s2 會指向同一個底層內存空間嗎?

輸出結果:

  1. 17608227  
  2. 17608227  
  3. 17608234  

從輸出結果來看,變量 s 和 s1 指向同一個內存地址。變量 s2 雖稍有偏差,但本質上也是指向同一塊。

因為其是字符串的切片操作,是從第 7 位索引開始,因此正好的 17608234-17608227 = 7。也就是三個變量都是指向同一塊內存空間,這是為什么呢?

這是因為在 Go 語言中,字符串都是只讀的,為了節省內存,相同字面量的字符串通常對應于同一字符串常量,因此指向同一個底層數組。

0 拷貝轉換

為什么會有人關注到 SliceHeader、StringHeader 這類運行時細節呢,一大部分原因是業內會有開發者,希望利用其實現零拷貝的 string 到 bytes 的轉換。

常見轉換代碼如下:

  1. func string2bytes(s string) []byte { 
  2.  stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s)) 
  3.  
  4.  bh := reflect.SliceHeader{ 
  5.   Data: stringHeader.Data, 
  6.   Len:  stringHeader.Len, 
  7.   Cap:  stringHeader.Len, 
  8.  } 
  9.  
  10.  return *(*[]byte)(unsafe.Pointer(&bh)) 

但這其實是錯誤的,官方明確表示:

the Data field is not sufficient to guarantee the data it references will not be garbage collected, so programs must keep a separate, correctly typed pointer to the underlying data.

SliceHeader、StringHeader 的 Data 字段是一個 uintptr 類型。由于 Go 語言只有值傳遞。

因此在上述代碼中會出現將 Data 作為值拷貝的情況,這就會導致無法保證它所引用的數據不會被垃圾回收(GC)。

應該使用如下轉換方式:

  1. func main() { 
  2.  s := "腦子進煎魚了" 
  3.  v := string2bytes1(s) 
  4.  fmt.Println(v) 
  5.  
  6. func string2bytes1(s string) []byte { 
  7.  stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s)) 
  8.  
  9.  var b []byte 
  10.  pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b)) 
  11.  pbytes.Data = stringHeader.Data 
  12.  pbytes.Len = stringHeader.Len 
  13.  pbytes.Cap = stringHeader.Len 
  14.  
  15.  return b 

在程序必須保留一個單獨的、正確類型的指向底層數據的指針。

在性能方面,若只是期望單純的轉換,對容量(cap)等字段值不敏感,也可以使用以下方式:

  1. func string2bytes2(s string) []byte { 
  2.  return *(*[]byte)(unsafe.Pointer(&s)) 

性能對比:

  1. string2bytes1-1000-4   3.746 ns/op  0 allocs/op 
  2. string2bytes1-1000-4   3.713 ns/op  0 allocs/op 
  3. string2bytes1-1000-4   3.969 ns/op  0 allocs/op 
  4.  
  5. string2bytes2-1000-4   2.445 ns/op  0 allocs/op 
  6. string2bytes2-1000-4   2.451 ns/op  0 allocs/op 
  7. string2bytes2-1000-4   2.455 ns/op  0 allocs/op 

會相當標準的轉換性能會稍快一些,這種強轉也會導致一個小問題。

代碼如下:

  1. func main() { 
  2.  s := "腦子進煎魚了" 
  3.  v := string2bytes2(s) 
  4.  println(len(v), cap(v)) 
  5. func string2bytes2(s string) []byte { 
  6.  return *(*[]byte)(unsafe.Pointer(&s)) 

輸出結果:

  1. 18 824633927632 

這種強轉其會導致 byte 的切片容量非常大,需要特別注意。一般還是推薦使用標準的 SliceHeader、StringHeader 方式就好了,也便于后來的維護者理解。

總結

在這篇文章中,我們介紹了字符串(string)和切片(slice)的兩個運行時表現,分別是 StringHeader 和 SliceHeader。

同時了解到其運行時表現后,我們還針對其兩者的地址指向,常見坑進行了說明。

最后我們進一步深入,面向 0 拷貝轉換的場景進行了介紹和性能分析。

你平時有沒有遇到過這塊的疑惑或問題呢,歡迎大家一起討論!

參考

Go語言slice的本質-SliceHeader

數組、字符串和切片

零拷貝實現string 和bytes的轉換疑問

 

責任編輯:武曉燕 來源: 腦子進煎魚了
相關推薦

2021-11-10 15:37:49

Go源碼指令

2022-01-05 11:40:36

Go特性語言

2025-06-27 09:32:47

GoRedis單線程

2022-08-02 10:01:34

Import語句ES模塊

2020-11-10 10:26:16

串口打印工具

2024-09-02 00:30:41

Go語言場景

2024-10-09 08:54:31

2023-12-12 08:41:01

2015-10-23 09:34:16

2021-10-14 06:52:47

算法校驗碼結構

2022-09-29 15:32:58

云計算計算模式

2024-09-18 07:00:00

消息隊列中間件消息隊列

2022-03-18 12:46:56

Go 語言編程語言

2022-05-09 10:47:08

登錄SpringSecurity

2024-04-15 00:04:00

APP開發

2022-03-10 08:25:27

JavaScrip變量作用域

2019-12-12 09:23:29

Hello World操作系統函數庫

2021-09-13 19:28:42

JavaNetty開發

2024-04-07 00:00:00

ESlint命令變量

2024-05-28 09:12:10

點贊
收藏

51CTO技術棧公眾號

色久视频在线播放| 日本精品在线免费观看| 欧美日韩美女| 国产精品美女久久久久久久 | 国产成+人+综合+亚洲欧美| 日韩毛片视频在线看| 国产嫩草一区二区三区在线观看| 久久久成人免费视频| 亚洲精品成人无限看| 亚洲精品久久在线| 爱豆国产剧免费观看大全剧苏畅 | 日本韩国精品一区二区| 美女视频网站久久| 久久久久久一区二区三区| 国产成人一区二区在线观看| 综合久久成人| 欧美人与性动xxxx| 国产主播在线看| 91网址在线观看| 久久精品水蜜桃av综合天堂| av一区观看| 中文字幕一区二区人妻| 99精品视频免费全部在线| 日韩视频免费观看| 最近中文字幕在线mv视频在线| 日韩成人在线观看视频| 欧美色国产精品| 欧美 激情 在线| 久草在线视频资源| 综合在线观看色| 四虎影视永久免费在线观看一区二区三区| www.我爱av| 久久国产剧场电影| 国产精品91免费在线| wwwxxx亚洲| 伊人久久综合| 九九热最新视频//这里只有精品| 国产成人免费观看网站| 美女久久99| 日韩电影第一页| 亚洲黄色小说在线观看| 国产成人久久精品一区二区三区| 欧美在线免费播放| www.亚洲天堂网| 一区二区电影免费观看| 疯狂做受xxxx高潮欧美日本| 日韩视频在线视频| 成人在线高清免费| 亚洲最大成人网4388xx| 欧美日韩dvd| 羞羞视频在线观看免费| 亚洲免费视频中文字幕| 一区二区三区日韩视频| 黄色小网站在线观看| 136国产福利精品导航| 一本一道久久a久久综合精品| 国产大片在线免费观看| 国产日韩精品一区二区三区| 欧美在线视频二区| 成年网站在线| 国产精品久久久久久久岛一牛影视 | 久久免费精品视频| 日韩av电影网| 国产视频一区三区| 国产91在线播放精品91| 国产精品传媒在线观看| 麻豆精品视频在线观看免费| 成人精品一区二区三区| 精品国自产拍在线观看| 成人午夜电影小说| 精品日本一区二区| 噜噜噜在线观看播放视频| 国产日韩欧美一区二区三区综合| 欧美lavv| 精品视频在线一区二区| 一区二区三区日本| 国产成人精品视频免费看| 欧美大胆性生话| 欧美午夜电影网| 国产毛片久久久久久| 超碰在线一区| 国产一区二区三区久久精品| 四虎影院中文字幕| 亚洲深夜av| 国产精品久久久久久久久久三级| 97精品久久人人爽人人爽| 精品一区免费av| 国产精品一 二 三| 国产高清视频在线| 亚洲综合一区二区精品导航| 免费高清在线观看免费| 婷婷激情成人| 亚洲的天堂在线中文字幕| 蜜桃av乱码一区二区三区| 亚洲字幕久久| 青草成人免费视频| 精品人妻一区二区三区蜜桃| 2023国产精品| 男女啪啪免费观看| 亚洲精品555| 精品国产精品网麻豆系列| 国产美女免费网站| 亚洲电影在线| 91在线免费视频| 久久天堂电影| 亚洲成年人网站在线观看| 九色91popny| 天堂网av成人| 欧美日韩电影在线观看| 午夜精品免费观看| 成人在线视频首页| 影音先锋欧美资源| 毛片在线网站| 日韩欧美国产一区二区在线播放 | 国产成人午夜视频网址| 亚洲黄色小说网| 国产精品乱码人人做人人爱| 欧洲黄色一级视频| 99精品中文字幕在线不卡| 搡老女人一区二区三区视频tv| 久久夜色精品亚洲| 国产成人在线视频免费播放| 亚洲一区二区三区免费看| 欧美久久天堂| 亚洲国产精品va在看黑人| www.99re7| 日本vs亚洲vs韩国一区三区二区 | 97国产超碰| 欧美性天天影视| 欧美亚洲综合一区| 日韩在线免费观看av| 99精品国产99久久久久久福利| 亚洲www视频| 米奇精品一区二区三区| 欧美三级电影网| 亚洲区自拍偷拍| 午夜在线视频观看日韩17c| 国产精品视频福利| 韩国成人免费视频| 精品国产电影一区二区| 久久久久久久久久久97| 国产精品影视在线观看| 亚洲最新免费视频| 57pao成人永久免费| 日韩一区二区av| 中文字幕在线视频免费| 日本一区二区在线不卡| chinese少妇国语对白| 欧美禁忌电影网| 国产suv精品一区二区| 日韩三级电影网| 欧美性xxxx在线播放| 成年人在线观看av| 久久国产精品久久久久久电车| 久久久久久一区| 桃色一区二区| 国产亚洲精品一区二555| 亚洲大尺度在线观看| 中文在线一区二区| 999在线观看| 亚洲女同一区| 国产精品jizz视频| 涩涩网在线视频| 亚洲欧美一区二区激情| 中国一级特黄视频| 最新国产成人在线观看| 无码国产精品久久一区免费| 国产精品久久| 蜜桃视频在线观看成人| 天然素人一区二区视频| 日韩视频在线免费| 风流少妇一区二区三区91| 午夜国产精品一区| 最近中文字幕免费| 精品一区二区三区免费| 国产高清不卡无码视频| 巨人精品**| 国产激情综合五月久久| 美女免费久久| 亚洲韩国青草视频| 超碰在线免费97| 亚洲综合自拍偷拍| 久久成人激情视频| 国产丶欧美丶日本不卡视频| 欧美日韩一道本| 日韩欧美精品| 国产精品成人一区二区三区| 日本免费久久| 欧美成人精品三级在线观看| 视频一区二区三区国产| 欧美妇女性影城| 亚州国产精品视频| 国产精品久久一卡二卡| 香蕉视频免费网站| 琪琪一区二区三区| www.xxx麻豆| 日韩av在线中文字幕| 国产一区二区精品免费| 福利一区二区| 久久久久女教师免费一区| 国产小视频在线| 日韩精品一区二区三区swag| 国产日韩在线免费观看| 亚洲3atv精品一区二区三区| 手机免费观看av| 91色综合久久久久婷婷| 午夜免费视频网站| 奇米精品一区二区三区在线观看 | 日韩国产欧美区| 国产一区二区三区在线观看| 岛国精品视频在线播放| 欧美国产日韩综合| 国产精品天天看| 欧美做受喷浆在线观看| 国产黄色成人av| 激情黄色小视频| 日韩专区中文字幕一区二区| 99国产精品白浆在线观看免费| 日韩国产一区| 日本高清久久一区二区三区| 99国产精品久久一区二区三区| 成人h视频在线| 精品免费av一区二区三区| 97精品免费视频| 欧美女同一区| 免费91在线视频| 欧美18一19xxx性| 中文字幕久久久| 黄色电影免费在线看| 亚洲精品一二区| 亚洲av片在线观看| 亚洲成人av片| 成人无码一区二区三区| 日韩三级高清在线| 99精品在线看| 91精品国产手机| 国产原创中文av| 欧美人牲a欧美精品| 91久久精品无码一区二区| 欧美视频在线观看一区二区| 999视频在线| 91福利区一区二区三区| 国产农村妇女aaaaa视频| 欧美午夜视频在线观看| 天天操天天干视频| 欧美丝袜一区二区三区| www.国产毛片| 在线视频你懂得一区二区三区| 中文字幕日韩免费| 在线观看不卡视频| 91成人国产综合久久精品| 欧美精品三级日韩久久| 国产普通话bbwbbwbbw| 日韩女优视频免费观看| 亚洲精品国产精品乱码不卡| 欧美成人精品二区三区99精品| 女人18毛片水真多18精品| 亚洲福利影片在线| 欧美巨乳在线| 自拍偷拍亚洲一区| 操你啦在线视频| 欧美国产日产韩国视频| 波多野结衣精品| 日韩av大片免费看| 国产福利亚洲| av一区二区在线看| 米奇777超碰欧美日韩亚洲| 色噜噜色狠狠狠狠狠综合色一| 欧美亚洲国产精品久久| 中文字幕人成一区| 伊人成人在线视频| 免费观看成人在线视频| 理论片日本一区| youjizz.com日本| 久久久久久**毛片大全| 在线观看天堂av| 亚洲尤物视频在线| 中文字幕日韩免费| 日韩欧美国产成人一区二区| 婷婷色在线视频| 一本色道久久综合亚洲精品小说| 免费网站成人| 性亚洲最疯狂xxxx高清| 成人黄色免费短视频| 亚洲xxxx3d| 亚洲高清极品| 国产成年人在线观看| 亚洲免费观看| 国产三级国产精品国产专区50| 国产精品亚洲а∨天堂免在线| 欧美性xxxx图片| 亚洲男人的天堂在线aⅴ视频| 国产精品7777777| 88在线观看91蜜桃国自产| 香蕉av一区二区三区| 两个人的视频www国产精品| 日韩电影毛片| 91亚洲精华国产精华| 九九视频免费观看视频精品| 日本一道在线观看| 日韩av在线播放中文字幕| 国产一精品一aⅴ一免费| 国产精品热久久久久夜色精品三区| 免费网站观看www在线观| 欧美系列一区二区| 少妇一区二区三区四区| 久久国产精品偷| 日韩精品三区| 精品一区二区三区日本| 欧美精品网站| 日韩av片专区| 日本一区二区三区在线不卡| 国产无遮挡裸体免费视频| 制服.丝袜.亚洲.中文.综合| 国产精品视频一区二区久久| 77777少妇光屁股久久一区| 精品国产亚洲日本| 一道精品一区二区三区| 老**午夜毛片一区二区三区 | 成人在线视频国产| 欧美重口乱码一区二区| 91久久视频| 午夜性福利视频| 亚洲男人的天堂一区二区| 中文字幕永久免费视频| 亚洲欧洲一区二区三区在线观看| 不卡av免费观看| 97人人澡人人爽| 亚洲精品在线观看91| 亚洲精品午夜在线观看| 国产日本欧洲亚洲| 怡红院av久久久久久久| 亚洲人成电影网站色| 欧美日韩美女| 欧美日韩最好看的视频| 久久大逼视频| 国产激情在线免费观看| 欧美性感美女h网站在线观看免费| 日韩中文字幕观看| 午夜欧美不卡精品aaaaa| 亚洲福利合集| www.男人天堂网| 国产91精品欧美| 五月天婷婷网站| 亚洲精品福利在线| 一二三四视频在线中文| 久久精品一区二区三区不卡免费视频| 亚洲人成免费| 三级男人添奶爽爽爽视频| 丰满岳妇乱一区二区三区| 日本不卡视频一区二区| 国产91在线播放九色快色| 欧美日韩精品一区二区视频| 色www免费视频| 综合分类小说区另类春色亚洲小说欧美| 一级黄色片免费| 不卡av在线播放| 成人直播在线观看| 日本免费不卡一区二区| 久久一日本道色综合| 亚洲av综合一区| 精品国产一区二区三区四区在线观看| **欧美日韩在线| 老司机激情视频| bt欧美亚洲午夜电影天堂| 日本视频在线观看免费| 一本色道久久综合狠狠躁篇的优点 | 国产精品久久久免费观看| 91久久精品网| 成年人黄视频在线观看| 国产精品国产精品| 鲁大师成人一区二区三区| 林心如三级全黄裸体| 欧美一区二区三区电影| 成人免费网站观看| 日韩精品国内| 国产乱对白刺激视频不卡| 欧美日韩精品区| 中文字幕亚洲欧美日韩在线不卡 | 奇米精品一区二区三区四区| 黄色a级片在线观看| 日韩电影中文 亚洲精品乱码| 日本.亚洲电影| 久久久久久久久久久综合| 久久久久综合网| 国产激情久久久久久熟女老人av| 91精品国产91久久久| 99精品视频在线| 成人性生活免费看| 欧美丰满少妇xxxxx高潮对白| 成年网站在线视频网站| 亚洲一二区在线| 成人av手机在线观看| 中文字幕在线一| 91精品国产免费久久久久久| 久久国产亚洲精品| yy6080午夜| 欧美一二三区在线| 无人区在线高清完整免费版 一区二| 国产香蕉一区二区三区|