Maximaler Speicher, den malloc zuweisen kann

Lesezeit: 12 Minuten

Benutzeravatar von Vikas
Vikas

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

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

Auch wenn ein Programm den Speicherverbrauch auf ein bestimmtes Niveau überschreitet, funktioniert der Computer nicht mehr, da andere Anwendungen nicht genügend Speicher erhalten, den sie benötigen.

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 brechen würde, aber mein Computer blieb hängen, da es sich um eine Endlosschleife handelte.

Ich habe ungefähr eine Stunde gewartet und musste schließlich meinen Computer zwangsweise herunterfahren.

Einige Fragen:

  • Weist malloc auch Speicher von HD zu?
  • Was war der Grund für das obige Verhalten?
  • Warum ist die Schleife zu keinem Zeitpunkt unterbrochen?
  • Warum gab es keinen Zuordnungsfehler?

  • Wie auch immer, warum malloc(4) und warum nicht malloc(4096) oder malloc(8192) oder sonst ?

    – Andrej Ciobanu

    9. Mai 2010 um 18:56 Uhr

  • Natürlich kann es alles sein, was ein Vielfaches von sizeof int ist. Ist es nicht?

    – Vikas

    9. Mai 2010 um 19:04 Uhr

  • caste das Ergebnis von malloc nicht in C

    – phuklv

    31. Dezember 2016 um 7:28 Uhr

  • Nein, es gibt einen sehr signifikanten Unterschied zwischen großen Mallocs wie malloc(1ULL<<30) gegen viele kleine Mallocs. Ihnen wird der virtuelle Adressraum auf die erste Weise ausgehen, bevor Ihnen RAM+Swap ausgeht, um die Buchhaltungsinformationen zu speichern, anstatt Swap-Thrashing durchzuführen, da Sie den gesamten physischen RAM verbrauchen. Wenn Ihre Zuordnungen viele Seiten umfassen, bleiben die meisten Seiten unberührt, selbst wenn malloc zu Beginn jeder Zuordnung Buchhaltungsinformationen speichert. Und winzige Zuweisungen benötigen mehr Platz für Buchhaltung und Ausrichtung als für die eigentliche 4-Byte-Zuweisung, also wenn Sie die gesamte zugewiesene Größe zählen würden, wäre das ein enormer Overhead.

    – Peter Cordes

    25. August um 13:04 Uhr


Benutzeravatar von Alex Martelli
Alex Martell

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

Falsch: Die meisten Computer/Betriebssysteme werden unterstützt virtuell Arbeitsspeicher, gesichert durch Festplattenspeicher.

Einige Fragen: tut malloc Speicher auch von HDD zuweisen?

malloc fragt das Betriebssystem, das wiederum möglicherweise etwas Speicherplatz benötigt.

Was war der Grund für das obige Verhalten? Warum brach die Schleife zu keinem Zeitpunkt?

Warum gab es keinen Zuordnungsfehler?

Sie haben einfach zu wenig auf einmal verlangt: Die Schleife wäre schließlich unterbrochen worden (lange nachdem Ihr Computer aufgrund des großen Überschusses an virtuellem gegenüber physischem Speicher und dem daraus resultierenden superhäufigen Festplattenzugriff, einem Problem, das als “Thrashing “), aber es hat Ihre Geduld schon vorher erschöpft. Versuchen Sie stattdessen, z. B. ein Megabyte auf einmal zu erhalten.

Wenn ein Programm den Speicherverbrauch auf ein bestimmtes Niveau überschreitet, funktioniert der Computer nicht mehr, da andere Anwendungen nicht genügend Speicher erhalten, den sie benötigen.

Ein vollständiger Stopp ist unwahrscheinlich, aber wenn eine Operation, die normalerweise einige Mikrosekunden dauern würde, am Ende (z. B.) zehn Millisekunden dauert, können diese vier Größenordnungen es sicherlich schaffen Gefühl als ob der Computer im Grunde stehen geblieben wäre, und was normalerweise eine Minute dauern würde, könnte eine Woche dauern.

  • Danke für die Info über malloc beim Zuweisen von Speicherplatz. Ich habe das vermutet, aber in vielen Artikeln wurde der Speicherplatz nicht erwähnt und es wurde geschrieben, dass malloc auf dem Heap und dem physischen Speicher alloziert. 🙂

    – Vikas

    9. Mai 2010 um 17:21 Uhr

  • @Richie Ich nehme auch an, dass Alex dort “prügeln” meinte.

    – Vikas

    9. Mai 2010 um 17:22 Uhr

  • @Richie und @Vikas, oops, ja, bearbeitet, um den Tippfehler zu korrigieren, danke!-)

    – Alex Martelli

    9. Mai 2010 um 19:50 Uhr

  • Ihre Speichergröße ist 1 GB bedeutet nicht, dass malloc den ganzen Weg dorthin gehen wird. Es hängt wirklich von der Menge an Speicher ab, die Ihr Betriebssystem Ihrem Prozess zuweist. Was, wenn man sich den Code ansieht, in diesem Fall sehr niedrig sein wird. Von da an wird Speicher auf Ihrem virtuellen Speicher zugewiesen.

    – Laz

    30. Mai 2010 um 15:03 Uhr

  • Tatsächlich kann malloc auf einigen Plattformen erfolgreich sein, obwohl die angeforderte Größe die RAM+Swap-Größe überschreitet. Unter Linux zum Beispiel bedeutet die Frage nach Speicher zu mappen /dev/zero was wiederum bedeutet, dass Seiten einfach als Null markiert werden – es sei denn, Sie ändern den Inhalt, es muss nicht viel Speicher verbrauchen oder Speicherplatz auslagern.

    – Himmel König

    31. Juli 2015 um 14:00 Uhr

Benutzeravatar von Sebastian
Sebastian

Ich weiß, dass dieser Thread alt ist, aber für alle, die bereit sind, es selbst zu versuchen, verwenden Sie diesen Codeausschnitt

#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 dieser Code den Arbeitsspeicher auf, bis er vom Kernel getötet wird. Verwenden von calloc anstelle von malloc, um “faule Auswertung” zu verhindern. Ideen aus diesem Thread: Malloc Memory Questions

Dieser Code füllte schnell meinen Arbeitsspeicher (4 GB) und dann in etwa 2 Minuten meine 20-GB-Swap-Partition, bevor sie starb. 64bit Linux natürlich.

  • Ich habe gerade das gleiche Programm auf einer Maschine mit 192 GB Speicher/4 GB Swap ausprobiert. Innerhalb einer Minute verbrauchte es bis zu 175 GB, dann wurde der Swap langsam gefüllt. Als nur noch 24 KB Swap übrig waren, wurde es beendet.

    – Sebastian

    22. Januar 2013 um 7:59 Uhr

  • Was Sie “Lazy Evaluation” nennen, ermöglicht es dem Kernel vermutlich, eine Nullseite für jede Seite von zugewiesenem, aber ungeschriebenem Speicher zu verwenden. Komprimierung (insbesondere für Swap) und sogar Deduplizierung (wie derzeit von einigen Hypervisoren durchgeführt) können den tatsächlich erforderlichen Speicher reduzieren. Natürlich hat malloc Speicher-Overhead, Seitentabellen fügen Overhead hinzu, das Programm hat keinen Heap-Speicher, das Betriebssystem verwendet Speicher usw.

    – Paul A. Clayton

    17. März 2014 um 14:06 Uhr

  • Eine gute calloc(3) Die Implementierung berührt die Seiten nicht, nachdem sie sie erhalten hat mmap(2), weil sie bereits auf Null gesetzt sind. Der Grund, warum dies letztendlich den OOM-Killer auslöst, ist, dass die zusätzlichen Buchhaltungsinformationen von malloc Speicher verwenden. Wenn du strace es, du wirst sehen mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4fc4d14000. Die Zuweisungsgröße, 1052672, beträgt 1 MB + 4096, und diese zusätzliche Seite ist vermutlich das, was der malloc von glibc tatsächlich verschmutzt. zB auf meinem Desktop mit 5 GiB physischem Speicher kann ich calloc 16 GiB (in 1-MiB-Blöcken) ohne Festplattenaktivität.

    – Peter Cordes

    6. Juni 2016 um 17:29 Uhr

  • Die unberührten virtuellen Seiten werden alle immer noch auf die gleiche physisch genullte Seite abgebildet.

    – Peter Cordes

    6. Juni 2016 um 17:30 Uhr

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

Unter Ubuntu 19.04 zum Beispiel das können wir leicht erkennen malloc wird mit umgesetzt mmap(MAP_ANONYMOUS durch die Nutzung strace.

Dann man proc dann beschreibt wie /proc/sys/vm/overcommit_memory steuert die maximale Belegung:

Diese Datei enthält den Abrechnungsmodus für den virtuellen Speicher des Kernels. Werte sind:

  • 0: heuristisches Overcommit (dies ist die Voreinstellung)
  • 1: Immer überschreiben, nie prüfen
  • 2: Immer prüfen, niemals überschreiben

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“ wird.

Im Modus 1 gibt der Kernel vor, immer genug Speicher zu haben, bis der Speicher tatsächlich erschöpft ist. Ein Anwendungsfall für diesen Modus sind wissenschaftliche Computeranwendungen, die große Sparse-Arrays verwenden. In Linux-Kernelversionen vor 2.6.0 impliziert jeder Wert ungleich Null Modus 1.

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

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

wo:

  • total_RAM ist die Gesamtmenge an RAM auf dem System;
  • total_huge_TLB ist die Speichermenge, die für riesige Seiten vorgesehen ist;
  • overcommit_ratio ist der Wert in /proc/sys/vm/overcommit_ratio; und
  • total_swap ist die Menge an Auslagerungsspeicher.

Beispielsweise ergibt diese Formel auf einem System mit 16 GB physischem RAM, 16 GB Swap, keinem Speicherplatz für große Seiten und einem overcommit_ratio von 50 ein CommitLimit 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-Kernel-Baum gibt auch einige Informationen, wenn auch lol ein bisschen weniger:

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

  • 0 Heuristische Overcommit-Behandlung. Offensichtliche Overcommits des Adressraums werden zurückgewiesen. Wird für ein typisches System verwendet. Es stellt sicher, dass eine ernsthaft wilde Zuweisung fehlschlägt, während Overcommit ermöglicht wird, um die Swap-Nutzung zu reduzieren. root darf in diesem Modus etwas mehr Speicher zuweisen. Dies ist die Standardeinstellung.

  • 1 Übertreibe es immer. Geeignet für einige wissenschaftliche Anwendungen. Ein klassisches Beispiel ist Code, der Sparse-Arrays verwendet und sich nur auf den virtuellen Speicher verlässt, der fast ausschließlich aus Nullseiten besteht.

  • 2 Übertreiben Sie es nicht. Die gesamte Adressraumfestschreibung 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 beendet wird, sondern gegebenenfalls Fehler bei der Speicherzuweisung erhält.

    Nützlich für Anwendungen, die sicherstellen möchten, dass ihre Speicherzuweisungen in Zukunft verfügbar sind, ohne jede Seite initialisieren zu müssen.

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 1 GiB und 1 TiB 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 finden 0 (die Standardeinstellung), aber auf meinem 32-GiB-RAM-Computer ist die 1-TiB-Zuweisung nicht zulässig:

mmap: Cannot allocate memory

Wenn ich jedoch unbegrenztes Overcommit aktiviere:

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

dann funktioniert die 1TiB-Zuweisung einwandfrei.

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

overcommit_ratio / 100

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

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

Bisher haben wir nur virtuellen Speicher zugewiesen.

Wenn Sie jedoch genügend dieser Seiten verwenden, muss Linux natürlich irgendwann damit beginnen, einige Prozesse zu beenden.

Ich habe das ausführlich dargestellt unter: Was ist RSS und VSZ in der Linux-Speicherverwaltung?

Benutzeravatar von human.js
human.js

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 dafür stdlib und stdio hinzu.
Dieser Auszug stammt von tiefe c Geheimnisse.

Benutzeravatar von mdma
mdma

malloc führt seine eigene Speicherverwaltung durch, verwaltet kleine Speicherblöcke selbst, verwendet aber letztendlich Win32 Heap-Funktionen Speicher zuzuweisen. Sie können sich vorstellen malloc als “Memory Reseller”.

Das Speichersubsystem von Windows besteht aus physischem Speicher (RAM) und virtuellem 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 tut dies transparent.

Standardmäßig ist der virtuelle Speicher aktiviert und verbraucht den verfügbaren Speicherplatz auf der Festplatte. Ihr Test wird also weiter ausgeführt, bis er entweder die volle Menge an virtuellem Speicher für den Prozess (2 GB bei 32-Bit-Windows) zugewiesen oder die Festplatte gefüllt hat.

Benutzeravatar von Martin Hennings
Martin Hennig

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

Außerdem ist das Argument von malloc ein size_t und der Bereich dieses Typs ist [0,SIZE_MAX]also das Maximum, das Sie können Anfrage ist SIZE_MAX, dessen Wert je nach Implementierung variiert und in definiert ist <limits.h>.

Benutzeravatar der Community
Gemeinschaft

Ich weiß nicht genau, warum das fehlgeschlagen ist, aber eine Sache ist, dass `malloc(4)” Ihnen vielleicht nicht wirklich 4 Bytes gibt, also ist diese Technik nicht wirklich ein genauer Weg, um Ihre maximale Heap-Größe zu finden.

Das habe ich durch meine Frage hier herausgefunden.

Wenn Sie beispielsweise 4 Byte Speicher deklarieren, könnte der Platz direkt vor Ihrem Speicher die Ganzzahl 4 enthalten, als Hinweis für den Kernel, wie viel Speicher Sie angefordert haben.

  • Tatsächlich gibt malloc normalerweise ein Vielfaches von 16 Bytes aus. Es gibt zwei Gründe. Einer ist, dass der Standard besagt, dass malloc einen Zeiger zurückgeben sollte, der mit jeder Datenausrichtung kompatibel ist. Daher konnten Adressen, die durch weniger als 16 Bytes getrennt waren, nicht zurückgegeben werden. Der andere Grund ist, dass freigegebene Blöcke normalerweise einige Daten speichern, die für die interne Speicherverwaltung verwendet werden, und ein zu kurzer Block – sagen wir 4 Bytes – ihn nicht speichern könnte.

    – kriss

    9. Mai 2010 um 16:47 Uhr


  • @kriss [i] Freigegebene Blöcke speichern normalerweise einige Daten, die für die interne Speicherverwaltung verwendet werden, und ein zu kurzer Block – sagen wir 4 Bytes – könnte ihn nicht speichern.[/i] Können Sie sagen, welche Art von Daten?

    – Vikas

    9. Mai 2010 um 17:24 Uhr

1412980cookie-checkMaximaler Speicher, den malloc zuweisen kann

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy