Verfügbaren Speicher bestimmen



  • Hallo zusammen,
    ich möchte gerne den dem Programm zur Verfügung stehenden Speicher bestimmen.
    Dazu nutze ich den folgenden Code:

    [code]
    #include<stdio.h>
    #include<stdlib.h>
    #define MB 1024
    
    size_t alloc_test(char *c){
    	size_t mb=1;
    	while ((c=(char*) malloc(mb*MB))!=NULL){
    		free(c);
    		mb++;
    	}
    
    	while ((c=(char*) malloc((--mb)*MB)) == NULL);
    	return mb;
    }
    
    int main(void){
    	char* c;
    	long int size;
    	size = alloc_test(c);
    	printf("Speicher: %lu\n", size);
    	if (size>0) free (c);
    	return 0;
    }
    [/code]
    

    Hier wird zunächst in 1024er-Schritten Speicher alloziert. Der malloc-Befehl (Zeile 😎 gibt ja keine Adresse, sondern den Nullzeiger zurück, wenn die Allokation nicht funktioniert hat, also in diesem Fall, wenn die gewünschte Größe den verfügbaren Speicher überschreitet. Also sollte doch die Funktion alloc_test(c) die korrekte Größe zurückliefern.
    Ich befürchte aber, dass das Programm in eine Endlosschleife geht, da es scheibar nicht terminiert.
    Wo liegt der Fehler, wenn es einen gibt?
    Schonmal danke und liebe Grüße,
    Progdummy



  • Meistens bestehen für Programme keine grossen Einschränkungen bezüglich des Ressourcenverbrauchs. Wenn der RAM voll ist, wird halt in den Auslagerungsspeicher geschrieben... Die einzige Begrenzung sind die 2GiB von 32-bit Systemen, da die Zeiger nicht mehr adressieren können. Ich glaube, dein System wird durch das malloc immer langsamer und langsamer bis es unbedienbar wird. Daher würde ich darauf vertrauen, dass immer genügend Speicher vorhanden ist. Ich selber teste den Rückgabewert von malloc eigentlich nie.

    Für ein Linux-System gilt das: getlimit(RLIMIT_AS, &rlim): "Since the value is a long, on machines with a 32-bit long either this limit is at most 2 GiB, or this resource is unlimited."



  • Ich selber teste den Rückgabewert von malloc eigentlich nie.

    ... würde ich schon machen. Was macht den Compiler bei malloc( 0) ?



  • Danke posixdummy,
    das ist beruhigend zu wissen, dass ich mich nicht großartig um den Speicher sorgen muss. 😉

    Du hast vermutet, dass das Programm durch das wiederholte malloc immer langsamer wird. Das glaube ich nicht, da ich in 1024ger Schritten vorgehe, wodurch malloc ja garnicht so häufig aufgerufen wird. Oder mache ich da einen Denkfehler?

    Da diese Funktion Teil einer Übungsaufgabe ist bin ich stark an der Fehlerquelle interessiert.
    Habt ihr da eine Idee, woran es liegen könnte?

    Liebe Grüße,
    ProgDummy



  • Progdummy schrieb:

    Du hast vermutet, dass das Programm durch das wiederholte malloc immer langsamer wird. Das glaube ich nicht, da ich in 1024ger Schritten vorgehe, wodurch malloc ja garnicht so häufig aufgerufen wird.

    Wenn das System zu swappen beginnt, könnte das deutlich auffallen.



  • Progdummy schrieb:

    da ich in 1024ger Schritten vorgehe, wodurch malloc ja garnicht so häufig aufgerufen wird. Oder mache ich da einen Denkfehler?

    malloc belegt soviel Byte wie im Argument übergeben wird. Bei 1024 Byte und 2 GByte zur Verfügung wird malloc 2 Millionen mal aufgerufen. 😮



  • DirkB schrieb:

    malloc belegt soviel Byte wie im Argument übergeben wird. Bei 1024 Byte und 2 GByte zur Verfügung wird malloc 2 Millionen mal aufgerufen. 😮

    Wir wissen ja nicht, ob der TE ein 32 Bit-OS nutzt. Bei WIN64 ist die Größe des virtuellen Speichers momentan 8192 GB.
    Und irgendwann wird er vielleicht bestimmt tatsächlich (1<<64)-1 Byte groß sein (1.678*107 TB). 😮 Naja, vielleicht auch "nur" (1<<63)-1 Byte.



  • mngbd schrieb:

    Progdummy schrieb:

    Du hast vermutet, dass das Programm durch das wiederholte malloc immer langsamer wird. Das glaube ich nicht, da ich in 1024ger Schritten vorgehe, wodurch malloc ja garnicht so häufig aufgerufen wird.

    Wenn das System zu swappen beginnt, könnte das deutlich auffallen.

    Das meinte ich.

    Scheppertreiber schrieb:

    ... würde ich schon machen. Was macht den Compiler bei malloc( 0) ?

    Ich habs getestet: er gibt den Wert 0x8f14008 zurück. Das genaue Verhalten ist nicht definiert und selbst wenn 0 zurückgegeben würde, stürzt das Programm beim nächsten Zugriff darauf ab und wechselt nicht ins undefinierte Verhalten.



  • Der letzte Post stammt von mir, ich habe den falschen Namen gewählt.



  • iosdumpy schrieb:

    Das genaue Verhalten ist nicht definiert und selbst wenn 0 zurückgegeben würde, stürzt das Programm beim nächsten Zugriff darauf ab und wechselt nicht ins undefinierte Verhalten.

    Was genau ist "undefiniertes Verhalten" denn für dich?



  • iosdumpy schrieb:

    Ich habs getestet: er gibt den Wert 0x8f14008 zurück. Das genaue Verhalten ist nicht definiert und selbst wenn 0 zurückgegeben würde, stürzt das Programm beim nächsten Zugriff darauf ab und wechselt nicht ins undefinierte Verhalten.

    Ist definiert, und zwar entweder NULL oder ein Zeiger, den man nicht verwenden darf, aber free()'n muss.



  • Erstmal danke an euch,
    ich habe jetzt mal den Wert für MB erhöht, damit das ganze in halbwegs akzeptabler Zeit abläuft.

    #include <stdio.h>
    #include <stdlib.h>
    #define MB 1024000
    
    size_t alloc_test(char *c){
    
    	size_t mb=1;
    
    	while ((c=(char*) malloc(mb*MB))!=NULL){
    		free(c);
    		mb++;
    	}
    
    	while ((c=(char*) malloc((--mb)*MB)) == NULL);
    
    	return mb;
    }
    
    int main(void){
    
    	char* c;
    	long int size;
    
    	size = alloc_test(c);
    	printf("Zur Verfuegung stehender Speicher in Megabyte: %lu\n", size);
    
    	if (size>0) {
    	  	printf("Reservierter Speicher mit Addresse %p wird nun freigegeben...\n", c);
    
    		free(c);
    	}
    
    	return 0;
    }
    

    Da Problem besteht jetzt in Zeile 30. Durch das free entsteht folgender Fehler:

    Speicherzugriffsfehler (Speicherabzug geschrieben)
    

    Woran kann das liegen?

    Liebe Grüße!



  • In der ersten Schleife testest Du was der Speicher hergibt und
    gibst den immer wieder frei.

    Dann zählst Du die mb wieder mit alloc() herunter ohne den freizugeben.

    Zurück gibt alloc_test() die mb (eine int).

    Du übergibst einen Stringpointer an test_alloc(), der muß eigentlich
    NULL bzw Nirwana sein wenn die Funktion aufhört.



  • Ok, ich dachte, der wäre nicht NULL, denn es wird ja in

    while ((c=(char*) malloc((--mb)*MB)) == NULL);
    

    die Passage

    c=(char*) malloc((--mb)*MB)
    

    so häufig aufgerufen, wie c==NULL ist. Dann wird noch einmal aufgerufen und festegestellt, dass c!=NULL ist, aber um das festzustellen, muss ja erstmal auf Gleichheit geprüft werden, d.h.

    c=(char*) malloc((--mb)*MB)
    

    müsste noch einmal aufgerufen werden. Scheinbar habe ich da aber einen Denkfehler.

    Demnach sollte doch kein Speicherzugriffsfehler auftauchen, wenn ich

    while ((c=(char*) malloc((--mb)*MB)) == NULL);
    

    durch

    while ((c=(char*) malloc((--mb)*MB)) == NULL);
    c=(char*) malloc((mb)*MB);
    

    ersetze. In diesem Fall gibt es aber trotzdem einen Zugriffsfehler.
    Warum?

    Danke und liebe Grüße!



  • Um er einmal kurz und zusammen zu fassen 😉 :

    Warum führt folgender Code zu einem Speicherzugriffsfehler?

    #include <stdio.h> 
    #include <stdlib.h> 
    #define MB 10240000
    
    size_t alloc_test(char *c){ 
    
        size_t mb=1; 
    
        while ((c=(char*) malloc(mb*MB))!=NULL){ 
            free(c); 
            mb++; 
        } 
    
        while ((c=(char*) malloc((--mb)*MB)) == NULL); 
        c = (char*) malloc(mb*MB);
    
        return mb; 
    } 
    
    int main(void){ 
    
        char* c; 
        long int size; 
    
        size = alloc_test(c); 
        printf("Zur Verfuegung stehender Speicher in Megabyte: %lu\n", size); 
    
        if (size>0) { 
              printf("Reservierter Speicher mit Addresse %p wird nun freigegeben...\n", c); 
    
            free(c); 
        } 
    
        return 0; 
    }
    

    Liebe Grüße!



  • #define MB 10240000 //was das für ne größe? definierst du ein mb neu 😕

    denke das letzte free(c) bringt den wurm rein..



  • Der Fehler ist, dass mehrmals allokierter Speicher nicht notwendigerweise am gleichen Ort ist.

    size_t alloc_test(char *c){
      // *c zeigt auf stelle 0x234A
      c=malloc(...);
      // *c zeigt auf stelle 0x765B
    }
    

    Nachher hast du keine Möglichkeit mehr herauszufinden, wo der neue *c hinzeigt.
    Daher: pointer auf pointer übergeben.

    size_t alloc_test(char **c){
        size_t mb=1;
        while ((*c=(char*) malloc(mb*MB))!=NULL){
            free(*c);
            mb++;
        }
        while ((*c=(char*) malloc((--mb)*MB)) == NULL);
        *c = (char*) malloc(mb*MB);
        return mb;
    }
    
    // in main:
    size = alloc_test(&c);
    

    Das bringt sicher einen grossen Wurm rein.



  • Funktioniert, genau da lag der Denkfehler.
    Danke!


Log in to reply