Maison >développement back-end >Golang >Pourquoi Go utilise-t-il moins de mémoire pour une tranche de longueur 100 000 que pour un tableau de longueur 100 000 ?

Pourquoi Go utilise-t-il moins de mémoire pour une tranche de longueur 100 000 que pour un tableau de longueur 100 000 ?

王林
王林avant
2024-02-09 10:12:09505parcourir

为什么 Go 对于长度为 100k 的切片使用的内存比长度为 100k 的数组要少?

Lorsque le langage Go gère les tranches et les tableaux, une tranche d'une longueur de 100 Ko utilise moins de mémoire qu'un tableau d'une longueur de 100 Ko. En effet, les tranches utilisent une combinaison de pointeurs et de longueurs dans leur implémentation sous-jacente, tandis que les tableaux nécessitent un espace mémoire contigu pour stocker les données. Puisque la longueur d'une tranche est variable, la mémoire peut être allouée et libérée dynamiquement, tandis qu'un tableau doit avoir une longueur fixe spécifiée lors de sa déclaration. Par conséquent, lors du traitement de grandes quantités de données, l’utilisation du découpage peut utiliser l’espace mémoire plus efficacement et réduire l’utilisation de la mémoire. C’est aussi l’un des avantages du langage Go lors du traitement de données à grande échelle.

Contenu de la question

Considérez le code suivant, j'ai alloué 4000 tableaux, chacun d'une longueur de 100 000 :

parentmap := make(map[int][100_000]int)
    for i := 0; i < 4000; i++ {
        parentmap[i] = [100_000]int{}
        time.sleep(3 * time.millisecond)
    }

Si j'exécute le programme localement et que j'analyse son utilisation de la mémoire, il commence à utiliser > 2 Go de mémoire.

Maintenant, si on change légèrement le code pour utiliser des tranches de tableau (mais aussi de longueur 100k) comme ceci :

parentMap := make(map[int][]int)
    for i := 0; i < 4000; i++ {
        parentMap[i] = make([]int, 100_000)
        time.Sleep(3 * time.Millisecond)
    }

Sur ma machine, la mémoire a culminé à environ 73 Mo. Pourquoi est-ce ?

Je pense que les deux fragments utiliseront à peu près la même mémoire pour les raisons suivantes :

  • Dans les deux cas, le runtime go allouera parentmap 的值。 go 这样做是因为如果它在堆栈上分配这些值,那么一旦当前函数超出范围,parentmap sur le tas et toutes les valeurs seront effacées.
  • Donc, le premier extrait de code alloue le tableau 4k directement sur le tas.
  • De plus, le deuxième fragment alloue un en-tête de tranche de 4k sur le tas. Chaque en-tête de tranche possède un pointeur vers un tableau unique de taille 100 000 (également sur le tas).
  • Dans les deux cas, il y a 4 000 tableaux sur un tas de taille 100 000. Par conséquent, des quantités de mémoire à peu près égales doivent être utilisées dans les deux cas.

J'ai lu : https://go.dev/blog/slices-intro. Mais je ne trouve pas de détails de mise en œuvre expliquant cela.

Solution de contournement

La version avec découpage pourrait bénéficier d'une allocation paresseuse. Rien ne tentera d'écrire dans les tampons de données de l'une de ces tranches, le système d'exploitation est donc libre de ne pas allouer de mémoire pour ces tampons jusqu'à ce qu'une écriture soit effectivement tentée. (Le système d'exploitation peut également réinitialiser paresseusement les tampons afin que les allocations ne soient pas forcées.)

De plus, la version avec un tableau nécessite que le tableau soit réellement copié dans la carte, ce qui signifie effectuer réellement l'écriture. Même si les valeurs écrites sont toutes des zéros, ce sont toujours des écritures, le système d'exploitation doit donc effectivement allouer de la mémoire pour les données à écrire.

Essayez d'écrire des données sur ces tranches, la version découpée devrait également occuper des gigaoctets de mémoire. (Je pense qu'une valeur par page de mémoire devrait suffire, mais il pourrait être plus facile de remplir la tranche avec des 1.)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer