wake-up-neo.net

Maximaler Speicher, den Malloc zuweisen kann

Ich habe versucht herauszufinden, wie viel Speicher ich auf meinem Computer maximal belegen kann (1 GB RAM 160 GB HD Windows-Plattform).

Ich habe gelesen, dass die maximale Speicherkapazität, die malloc zuweisen kann, auf den physischen Speicher (auf dem Heap) beschränkt ist.

Wenn ein Programm den Speicherverbrauch bis zu einem bestimmten Grad übersteigt, funktioniert der Computer nicht mehr, da andere Anwendungen nicht genügend Speicherplatz zur Verfügung haben.

Zur Bestätigung habe ich ein kleines Programm in C geschrieben:

int main(){  
    int *p;
    while(1){
        p=(int *)malloc(4);
        if(!p)break;
    }   
}

Ich hatte gehofft, dass es eine Zeit geben würde, in der die Speicherzuweisung fehlschlagen und die Schleife unterbrochen würde, aber mein Computer blieb hängen, da es sich um eine Endlosschleife handelte.

Ich wartete ungefähr eine Stunde und musste schließlich meinen Computer zwangsweise ausschalten.

Einige Fragen:

  • Weist malloc auch Speicher von HD zu?
  • Was war der Grund für obiges Verhalten?
  • Warum wurde die Schleife zu keinem Zeitpunkt unterbrochen?
  • Warum ist die Zuordnung fehlgeschlagen?
41
Vikas

Ich habe gelesen, dass der maximale Speicher, den malloc zuordnen kann, auf den physischen Speicher (auf dem Heap) beschränkt ist.

Falsch: Die meisten Computer/Betriebssysteme unterstützen virtuellen Speicher, der durch Speicherplatz gesichert ist.

Einige Fragen: reserviert malloc auch Speicher von der Festplatte?

malloc fragt das Betriebssystem, das wiederum möglicherweise Speicherplatz belegt.

Was war der Grund für obiges Verhalten? Warum hat die Schleife zu keiner Zeit unterbrochen?

Warum ist die Zuordnung fehlgeschlagen?

Sie haben nur zu wenig nachgefragt: Die Schleife wäre irgendwann unterbrochen worden (lange nachdem Ihr Computer aufgrund des großen Überschusses an virtuellem und physischem Speicher und des daraus resultierenden, sehr häufigen Festplattenzugriffs langsamer geworden ist). Dieses Problem wird als "Thrashing" bezeichnet ") aber es hat deine geduld schon lange erschöpft. Versuchen Sie, z. stattdessen jeweils ein Megabyte.

Wenn ein Programm den Speicherverbrauch bis zu einem bestimmten Grad übersteigt, funktioniert der Computer nicht mehr, da andere Anwendungen nicht genügend Speicherplatz zur Verfügung haben.

Ein Totalstopp ist unwahrscheinlich, aber wenn eine Operation, die normalerweise einige Mikrosekunden dauern würde, (z. B.) zehn Millisekunden in Anspruch nimmt, können diese vier Größenordnungen sicherlich das Gefühl hervorrufen Wenn der Computer im Grunde gestoppt hätte und was normalerweise eine Minute dauern würde, könnte eine Woche dauern.

47
Alex Martelli

Ich weiß, dass dieser Thread alt ist, aber für alle, die es selbst ausprobieren möchten, verwenden Sie diesen Code

#include <stdlib.h>

int main() {
int *p;
while(1) {
    int inc=1024*1024*sizeof(char);
    p=(int*) calloc(1,inc);
    if(!p) break;
    }
}

lauf

$ gcc memtest.c
$ ./a.out

beim Ausführen füllt sich dieser Code mit 1 RAM bis er vom Kernel getötet wird. Verwenden Sie calloc anstelle von malloc, um "Lazy Evaluation" zu verhindern. Ideen aus diesem Thread: Malloc Memory Questions

Dieser Code füllte schnell meine RAM (4Gb) und dann in ca. 2 Minuten meine 20Gb Swap Partition bevor sie starb. 64bit Linux natürlich.

25
Sebastian

malloc führt eine eigene Speicherverwaltung durch, wobei kleine Speicherblöcke selbst verwaltet werden. Letztendlich wird jedoch Win32 Heap-Funktionen zum Zuweisen von Speicher verwendet. Sie können sich malloc als "Speicherverkäufer" vorstellen.

Das Windows-Speichersubsystem umfasst physischen Speicher (RAM) und virtuellen Speicher (HD). Wenn der physische Speicher knapp wird, können einige der Seiten vom physischen Speicher in den virtuellen Speicher auf der Festplatte kopiert werden. Windows macht das transparent.

Standardmäßig ist der virtuelle Speicher aktiviert und belegt den verfügbaren Speicherplatz auf der Festplatte. Daher wird der Test so lange ausgeführt, bis entweder der gesamte virtuelle Speicher für den Prozess zugewiesen wurde (2 GB in 32-Bit-Fenstern) oder die Festplatte voll ist.

6
mdma

Versuche dies

#include <stdlib.h>
#include <stdio.h>

main() {
    int Mb = 0;
    while (malloc(1<<20)) ++Mb;
    printf("Allocated %d Mb total\n", Mb);
}

Fügen Sie dazu stdlib und stdio hinzu.
Dieser Auszug stammt aus tiefe Geheimnisse.

5
human.js

Ich weiß nicht genau, warum dies fehlgeschlagen ist, aber eines ist zu beachten, dass "malloc (4)" Ihnen möglicherweise nicht 4 Bytes liefert. Daher ist diese Technik nicht wirklich eine genaue Methode, um Ihre maximale Heap-Größe zu ermitteln.

Das habe ich aus meiner Frage herausgefunden hier .

Wenn Sie beispielsweise 4 Byte Arbeitsspeicher deklarieren, kann der Speicherplatz direkt vor Ihrem Arbeitsspeicher die Ganzzahl 4 enthalten, um dem Kernel anzuzeigen, wie viel Arbeitsspeicher Sie angefordert haben.

3
Chris Cooper

Gemäß C90-Standard wird garantiert, dass Sie mindestens ein Objekt mit einer Größe von 32 kByte erhalten können. Dies kann statischer, dynamischer oder automatischer Speicher sein. C99 garantiert mindestens 64 kByte. Informationen zu höheren Limits finden Sie in der Dokumentation Ihres Compilers.

Mallocs Argument ist ein size_t und der Bereich dieses Typs ist [0, SIZE_MAX]. Sie können also maximal request SIZE_MAX angeben. Dieser Wert variiert je nach Implementierung und ist in <limits.h>.

2
mav_2k

/proc/sys/vm/overcommit_memory Steuert das Maximum unter Linux

Unter Ubuntu 19.04 zum Beispiel wir können leicht sehen, dass malloc mit mmap(MAP_ANONYMOUS Implementiert wird, indem strace verwendet wird .

Dann beschreibt man proc, Wie /proc/sys/vm/overcommit_memory Die maximale Zuweisung steuert:

Diese Datei enthält den Abrechnungsmodus für den virtuellen Kernelspeicher. Werte sind:

  • 0: heuristisches Overcommit (dies ist die Standardeinstellung)
  • 1: Immer überbeanspruchen, niemals überprüfen
  • 2: Immer prüfen, niemals überbeanspruchen

Im Modus 0 werden Aufrufe von mmap (2) mit MAP_NORESERVE nicht geprüft, und die Standardprüfung ist sehr schwach, was zu dem Risiko führt, dass ein Prozess "OOM-killed" ausgeführt wird.

In Modus 1 gibt der Kernel vor, dass immer genügend Speicher vorhanden ist, bis der Speicher tatsächlich aufgebraucht ist. Ein Anwendungsfall für diesen Modus sind wissenschaftliche Computeranwendungen, die große, spärliche Arrays verwenden. In Linux-Kernel-Versionen vor 2.6.0 impliziert jeder Wert ungleich Null den Modus 1.

Im Modus 2 (verfügbar seit Linux 2.6) wird der gesamte zuweisbare virtuelle Adressraum (CommitLimit in/proc/meminfo) wie folgt berechnet

CommitLimit = (total_RAM - total_huge_TLB) * overcommit_ratio / 100 + total_swap

wo:

  • total_RAM ist der Gesamtbetrag von RAM auf dem System;
  • total_huge_TLB ist die Menge an Speicher, die für große Seiten reserviert ist.
  • overcommit_ratio ist der Wert in/proc/sys/vm/overcommit_ratio; und
  • total_swap ist die Menge an Swap Space.

Beispiel: Auf einem System mit 16 GB physischem RAM, 16 GB Swap, keinem für große Seiten reservierten Speicherplatz und einem overcommit_ratio von 50 ergibt diese Formel ein ComitLimit von 24 GB.

Wenn der Wert in/proc/sys/vm/overcommit_kbytes seit Linux 3.14 ungleich Null ist, wird CommitLimit stattdessen wie folgt berechnet:

CommitLimit = overcommit_kbytes + total_swap

Siehe auch die Beschreibung von/proc/sys/vm/admiin_reserve_kbytes und/proc/sys/vm/user_reserve_kbytes.

Documentation/vm/overcommit-accounting.rst im 5.2.1-Kernelbaum gibt auch einige Informationen, obwohl lol ein bisschen weniger:

Der Linux-Kernel unterstützt die folgenden Overcommit-Bearbeitungsmodi

  • 0 Heuristisches Overcommit-Handling. Offensichtliche Überlastungen des Adressraums werden abgelehnt. Wird für ein typisches System verwendet. Es stellt sicher, dass eine ernsthafte Wild-Allocation fehlschlägt, und ermöglicht gleichzeitig eine Überbeanspruchung, um die Swap-Nutzung zu reduzieren. root darf in diesem Modus etwas mehr Speicher zuweisen. Dies ist die Standardeinstellung.

  • 1 Immer überbeanspruchen. Geeignet für einige wissenschaftliche Anwendungen. Ein klassisches Beispiel ist Code mit spärlichen Arrays, der sich nur auf den virtuellen Speicher verlässt, der fast ausschließlich aus Nullseiten besteht.

  • 2 Überbeanspruchen Sie nicht. Das gesamte Adressraum-Commit für das System darf Swap + eine konfigurierbare Menge (Standard ist 50%) des physischen RAM nicht überschreiten. Abhängig von der Menge, die Sie verwenden, bedeutet dies in den meisten Situationen, dass ein Prozess beim Zugriff auf Seiten nicht abgebrochen wird, sondern gegebenenfalls Fehler bei der Speicherzuweisung angezeigt werden.

    Nützlich für Anwendungen, die ihre Speicherzuordnungen garantieren möchten, werden zukünftig verfügbar sein, ohne dass jede Seite initialisiert werden muss.

Minimales Experiment

Wir können den maximal zulässigen Wert leicht sehen mit:

haupt c

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char **argv) {
    char *chars;
    size_t nbytes;

    /* Decide how many ints to allocate. */
    if (argc < 2) {
        nbytes = 2;
    } else {
        nbytes = strtoull(argv[1], NULL, 0);
    }

    /* Allocate the bytes. */
    chars = mmap(
        NULL,
        nbytes,
        PROT_READ | PROT_WRITE,
        MAP_SHARED | MAP_ANONYMOUS,
        -1,
        0
    );

    /* This can happen for example if we ask for too much memory. */
    if (chars == MAP_FAILED) {
        perror("mmap");
        exit(EXIT_FAILURE);
    }

    /* Free the allocated memory. */
    munmap(chars, nbytes);

    return EXIT_SUCCESS;
}

GitHub upstream .

Kompilieren und ausführen, um 1GiB und 1TiB zuzuweisen:

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out 0x40000000
./main.out 0x10000000000

Wir können dann mit dem Zuordnungswert herumspielen, um zu sehen, was das System zulässt.

Ich kann keine genaue Dokumentation für 0 (Standardeinstellung) finden, aber auf meinem 32GiB RAM Computer ist die 1TiB-Zuordnung nicht möglich:

mmap: Cannot allocate memory

Wenn ich jedoch unbegrenztes Overcommit aktiviere:

echo 1 | Sudo tee /proc/sys/vm/overcommit_memory

dann funktioniert die 1TiB-Zuordnung einwandfrei.

Der Modus 2 Ist gut dokumentiert, aber ich bin faul, genaue Berechnungen durchzuführen, um dies zu überprüfen. Aber ich möchte nur darauf hinweisen, dass wir in der Praxis Folgendes zuteilen dürfen:

overcommit_ratio / 100

des gesamten Arbeitsspeichers, und overcommit_ratio ist standardmäßig 50, sodass wir ungefähr die Hälfte des gesamten Arbeitsspeichers zuweisen können.

VSZ vs RSS und der Out-of-Memory-Killer

Bisher haben wir gerade virtuellen Speicher zugewiesen.

Wenn Sie jedoch irgendwann genug von diesen Seiten verwenden, muss Linux damit beginnen, einige Prozesse zu beenden.

Ich habe das im Detail dargestellt unter: Was ist RSS und VSZ in der Linux-Speicherverwaltung