Historique de la question :
Les slices sont l'une des structures dynamiques clés en Go, apparues comme une alternative aux tableaux de taille fixe pour améliorer la commodité et l'efficacité de la mémoire. Ils permettent une manipulation flexible des sous-ensembles de tableaux, mais comportent un certain nombre de subtilités importantes pour un code performant et sécurisé.
Problème :
De nombreux développeurs ne comprennent pas exactement comment les slices sont structurés : un slice n'est pas lui-même un tableau, mais une structure contenant un pointeur vers un tableau, une longueur et une capacité (capacity). Cela peut conduire à des fuites de mémoire, des bugs lors du travail avec des copies et des effets inattendus lors de la modification du tableau d'origine.
Solution :
Un slice est un type :
type slice struct { ptr unsafe.Pointer len int cap int }
Lors de l'extension d'un slice avec append(), il peut se produire une réallocation du tableau sous-jacent, et toutes les anciennes références à l'ancien tableau resteront valides, mais pointeront vers d'anciennes données. Ignorer cette particularité entraîne des erreurs et des fuites de mémoire.
Exemple d'allocation de mémoire correcte et de copie :
src := []int{1,2,3,4,5} dst := make([]int, len(src)) copy(dst, src)
Un slice créé avec [:] partage le tableau sous-jacent, et leur modification s'influence mutuellement, sauf si une copie est effectuée.
Caractéristiques clés :
Que se passe-t-il en augmentant un slice via append en dépassant cap, si d’autres slices ont des références vers le même tableau ?
append en dépassant cap crée un tableau sous-jacent avec un nouvel emplacement en mémoire, et seul ce slice fera référence au nouveau tableau, tandis que les autres feront référence à l'ancien. C'est une cause fréquente de divergence de données.
Pourquoi est-il important de ne pas conserver des slices de petite taille à long terme, obtenus à partir d'un grand tableau ?
Même si le slice est très petit, son pointeur conserve une référence à l'ensemble du tableau sous-jacent, ce qui peut entraîner le maintien du grand tableau en mémoire et une fuite de mémoire.
Que se passe-t-il si on slice un tableau au-delà de ses limites ?
Cela déclenchera une panique : erreur d'exécution : limites du slice hors de portée.
La fonction lit un grand fichier dans un tableau d'octets et renvoie un slice des 100 premiers éléments. Ce slice est ensuite conservé longtemps, mais toute la mémoire pour le grand tableau reste en GC.
Avantages :
Inconvénients :
Immédiatement après l'obtention du slice, une copie de la portion nécessaire est réalisée dans un nouveau slice avec make et copy. L'ancien tableau est immédiatement oublié, et le GC libère la mémoire.
Avantages :
Inconvénients :