En Go, la conversion entre string et []byte entraîne généralement une nouvelle allocation de mémoire, car les chaînes sont immuables et les tranches de bytes sont mutables. Il existe des optimisations internes du compilateur (analyse des évasions), mais elles ne sont pas garanties et varient entre les versions de Go.
Conversion directe :
[]byte(s string): alloue toujours un nouveau tableau de bytes et copie les données.string(b []byte): copie également toujours les données du tableau de bytes dans une nouvelle chaîne.Zero allocation — une approche qui évite les allocations inutiles. La bibliothèque standard de Go propose une conversion non sécurisée via le package unsafe, permettant de référencer les mêmes données sans les copier. Cela ne devrait être utilisé qu'avec une compréhension complète des risques.
import ( "reflect" "unsafe" ) func BytesToString(b []byte) string { return *(*string)(unsafe.Pointer(&b)) } func StringToBytes(s string) []byte { sh := (*reflect.StringHeader)(unsafe.Pointer(&s)) bh := reflect.SliceHeader{ Data: sh.Data, Len: sh.Len, Cap: sh.Len, } return *(*[]byte)(unsafe.Pointer(&bh)) }
Dans la plupart des cas, il est préférable de ne pas utiliser ces techniques — elles compromettent la sécurité des données (il est possible de modifier le contenu d'une chaîne via une tranche partagée, ce qui peut entraîner des erreurs).
On demande souvent : "Est-il vrai que la conversion d'un string en []byte ne générera pas d'allocation si la chaîne est petite ou constante ?"
Réponse correcte : Non. Quelle que soit la taille de la chaîne, le compilateur créera toujours un nouveau tableau de bytes et copiera le contenu. Les exceptions ne concernent que les optimisations unsafe, qui ne garantissent pas la sécurité et ne sont pas soutenues par la documentation officielle de Go.
Histoire
L'équipe a écrit un service à fort chargement pour analyser des logs et convertissait constamment les chaînes d'entrée en tranches de bytes et vice versa pour le traitement. Dans des situations de pointe, le ramasse-miettes a dépensé jusqu'à 30 % du temps processeur à collecter des copies à courte durée de vie. Après profilage, il a été constaté que chaque conversion string↔[]byte allouait une zone de mémoire distincte. Après mise en œuvre de pools et redesign de l'API, une grande partie des conversions a pu être éliminée, réduisant la charge sur le GC de moitié.
Histoire
Un des développeurs a optimisé le travail avec JSON, utilisant la conversion unsafe bytes→string pour éviter les allocations. Au début, le gain de performance était perceptible, mais un mois plus tard, des plantages sont survenus : un certain buffer de bytes était réutilisé, et la chaîne faisait référence à des données anciennes modifiées. La seule solution a été de revenir aux copies standard et de revoir l'API inter-processus.
Histoire
Lors de la transmission de grandes données binaires sur le réseau, ils ont décidé d'"optimiser" la sérialisation en utilisant BytesToString (sans copie). Un jour, la chaîne envoyée s'est révélée publiquement visible, et le contenu de la tranche de bytes a immédiatement été écrasé, entraînant l'envoi de déchets et une fuite de données privées dans le journal des paquets erronés. Au final, la déduplication de la mémoire a abouti à une fuite de données privées !