1 回答

TA貢獻1801條經驗 獲得超16個贊
雖然@blackgreen 是正確的,但我會稍微擴展一下推理。
該sync.Map
類型被明確定義為在 上進行操作interface{}
。
現在請記住,在 Go 中,接口不僅僅是類型系統使用的抽象;相反,您可以擁有接口類型的值,并且這些值的內存表示是struct
包含兩個指針——指向描述存儲在變量中的值的動態類型的內部對象,以及指向值本身(或副本它由運行時在堆上創建)。
這意味著,如果您要在 中存儲指向任何內容的指針,則存儲的sync.Map
任何此類指針都將被轉換為類型的值,interface{}
并且它將在 中占據完全相同的空間sync.Map
。
相反,如果您將類型的值net.Conn
直接存儲在那里,它們將被直接存儲——僅僅是因為它們已經是接口值,所以 Go 只會復制這對指針。
從表面上看,這兩種方法在使用的空間方面都差不多,但請容忍我。
要存儲指向容器數據類型(net.Conn
例如sync.Map
編譯器安排確保原始net.Conn
值直接在堆上分配。
換句話說,存儲指向接口類型變量的指針可能(并且通常會——由于典型代碼的組織方式)在內存使用方面更加浪費。
此外,大多數取消引用(指針追逐)往往會破壞 CPU 緩存;這不會改變游戲規則,但當您在緊密循環中迭代集合時可能會增加幾微秒。
話雖如此,我建議不要完全放棄在容器中存儲指針,例如sync.Map
:偶爾它會派上用場——例如,為了將數組重用于切片,您通常存儲指向此類數組的第一個元素的指針。
添加回答
舉報