Heim >Backend-Entwicklung >Golang >Warum benötigt Go für ein Slice mit einer Länge von 100 KB weniger Speicher als für ein Array mit einer Länge von 100 KB?

Warum benötigt Go für ein Slice mit einer Länge von 100 KB weniger Speicher als für ein Array mit einer Länge von 100 KB?

王林
王林nach vorne
2024-02-09 10:12:09505Durchsuche

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

Wenn die Go-Sprache Slices und Arrays verarbeitet, benötigt ein Slice mit einer Länge von 100 KB weniger Speicher als ein Array mit einer Länge von 100 KB. Dies liegt daran, dass Slices in ihrer zugrunde liegenden Implementierung eine Kombination aus Zeigern und Längen verwenden, während Arrays zusammenhängenden Speicherplatz zum Speichern von Daten benötigen. Da die Länge eines Slice variabel ist, kann Speicher dynamisch zugewiesen und freigegeben werden, während für ein Array bei der Deklaration eine feste Länge angegeben werden muss. Daher kann die Verwendung von Slicing bei der Verarbeitung großer Datenmengen den Speicherplatz effizienter nutzen und die Speichernutzung reduzieren. Dies ist auch einer der Vorteile der Go-Sprache bei der Verarbeitung großer Datenmengen.

Frageninhalt

Betrachten Sie den folgenden Code, ich habe 4000 Arrays mit jeweils 100.000 Längen zugewiesen:

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

Wenn ich das Programm lokal ausführe und seine Speichernutzung analysiere, beginnt es, mehr als 2 GB Speicher zu verbrauchen.

Wenn wir nun den Code leicht ändern, um Array-Slices (aber auch mit einer Länge von 100 KB) wie folgt zu verwenden:

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

Auf meinem Computer erreichte der Speicher seinen Höhepunkt bei etwa 73 MB. Warum ist das so?

Ich denke, dass beide Fragmente aus folgenden Gründen ungefähr den gleichen Speicher nutzen werden:

  • In beiden Fällen weist die Go-Laufzeit parentmap 的值。 go 这样做是因为如果它在堆栈上分配这些值,那么一旦当前函数超出范围,parentmap auf dem Heap zu und alle Werte werden gelöscht.
  • Das erste Code-Snippet ordnet also das 4k-Array direkt auf dem Heap zu.
  • Außerdem weist das zweite Fragment einen 4K-Slice-Header auf dem Heap zu. Jeder Slice-Header hat einen Zeiger auf ein eindeutiges Array der Größe 100 KB (auch auf dem Heap).
  • In beiden Fällen gibt es 4K-Arrays auf einem Heap der Größe 100K. Daher sollte in beiden Fällen ungefähr die gleiche Speichermenge verwendet werden.

Ich habe gelesen: https://go.dev/blog/slices-intro. Ich kann jedoch keine Implementierungsdetails finden, die dies erklären.

Problemumgehung

Die Version mit Slicing könnte von der Lazy Allocation profitieren. Es wird nicht versucht, in die Datenpuffer in einem dieser Slices zu schreiben, daher steht es dem Betriebssystem frei, diesen Puffern erst dann tatsächlich Speicher zuzuweisen, wenn tatsächlich ein Schreibversuch unternommen wird. (Das Betriebssystem kann Puffer auch langsam auf Null initialisieren, sodass Zuweisungen nicht erzwungen werden.)

In der Zwischenzeit erfordert die Version mit einem Array, dass das Array tatsächlich in die Karte kopiert wird, was bedeutet, dass der Schreibvorgang tatsächlich ausgeführt wird. Selbst wenn die geschriebenen Werte alle Nullen sind, handelt es sich dennoch um Schreibvorgänge, sodass das Betriebssystem tatsächlich Speicher für die zu schreibenden Daten zuweisen muss.

Versuchen Sie, Daten in diese Slices zu schreiben. Die Sliced-Version sollte ebenfalls Gigabyte Speicher beanspruchen. (Ich denke, ein Wert pro Speicherseite sollte ausreichen, aber es könnte einfacher sein, das Slice mit 1s zu füllen.)

Das obige ist der detaillierte Inhalt vonWarum benötigt Go für ein Slice mit einer Länge von 100 KB weniger Speicher als für ein Array mit einer Länge von 100 KB?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen