Probleme bei calloc - bei großen Feldern



  • Hallo.

    bei meinem Code werden Koordinaten eingelesen (siehe Posting: Fehlersuche).

    Die Koordinaten werden in einem struct TPoint gespeichert.

    typedef struct {
    	//Point coordinatess
    	double x, y, z;
    } TPoint;
    

    Der Code funktioniert wurnderbar bei einem Fall mit 1.4 Mio. Koordinaten.
    Bei 10 Mio. kommt es zum Programmabsturz. Ich konnte den Fehler ermitteln.

    Beim lesen der Knoten wird ein Feld fpNode vom Typ TPoint angelegt.

    unsinged long nNode = 10000000 //Zehn Million 
    TPoint * fpNode = (TPoint *)calloc(nNode, sizeof(TPoint));
    
    //Test
    printf("x[3]: %2.2f\n", fpNode[2].x); //Hier, stuerzt das Programm ab
    

    Mit

    nNode = 1400000 //1.4 Mio
    

    funktioniert das Programm wunderbar.

    Arbeitsspeicher habe ich genügend.
    Nutze den TCC- und den LCC Compiler.

    Vielen Dank,
    Jan


  • Mod

    Das ist nicht das komplette Programm. Du erzeugst irgendwo ganz woanders einen Fehler, der sich bloß an dieser Stelle äußert.

    Um ganz blöde Fehler auszuschließen, mach mal erst einmal all diese dummen, unnötigen Pointercasts weg:

    TPoint * fpNode = (TPoint *)calloc(nNode, sizeof(TPoint));
    

    ->

    TPoint * fpNode = calloc(nNode, sizeof(TPoint));
    

    Wir sind hier schließlich nicht in C++ und in C++ würde man das auch nicht so machen. So kann dein C-Compiler seine Arbeit korrekt verrichten und dir auch eventuelle Fehler melden.

    Ansonsten siehe den dritten Link in meiner Signatur, wie du Code so posten kannst, dass wir dir auch konkret helfen können.



  • Nicht genug Speicher? Insbesondere, wenn du die Funktion mehrfach aufrufst. calloc gibt in so einem Fall NULL zurück; den Fall solltest du abfangen.



  • Du musst fpNode auf korrekte Ausführung von calloc prüfen, also

    if( fpNode!=NULL )
    

    Anderfalls konnte dein Laufzeitsystem nicht genug Speicher bereitstellen.
    Bei 32-Bit Compilern gilt üblicherweise die 4GB Grenze, willst du mehr reservieren musst du auf 64Bit umsteigen.



  • ...tatsächlich NULL zurück.

    Ich habe Windows Ultimate 64 bit und 32 GB RAM.
    Der Taskmanager zeigt 2 GB Speicher an beim Absturz.

    Achso - brauch ich auch ne 64 Bit Compilerversion von TCC bzs. LCC?



  • CJens schrieb:

    Ich habe Windows Ultimate 64 bit und 32 GB RAM.

    Das hat überhaupt nichts zu sagen, entscheidend ist der Compiler bzw. dessen erzeugtes Programm.

    CJens schrieb:

    Achso - brauch ich auch ne 64 Bit Compilerversion von TCC bzs. LCC?

    Ja, oder einen anderen 64Bit-fähigen Windows C-Compiler.



  • Wenn du in irgendeinem 32-Bit-Programm auf irgendeiner Plattform 4 GB am Stück reserviert kriegst, bin ich echt beeindruckt. Üblicherweise gehen erstmal 1-2 GB des virtuellen Adressraums für das Betriebssystem drauf, und dann gibt es da noch Threadstacks, dedizierte Bereiche für memory mapping und derlei, und wenn man nicht gerade unter Laborbedingungen arbeitet auch noch Dinge anderer Programmteile auf dem Heap. Dessen freie Bereiche nicht an einem Stück liegen müssen.

    Unter Windows sind in 32-Bit-Prozessen per Default 2GB fürs Betriebssystem reserviert, das ist erstmal der größte Posten (darum schmiert das auch bei 2GB Auslastung ab). Es ist möglich, diesen Anteil auf 1 GB zu verringern, wenn du nicht grad viel mit Grafik machst (ein großer Teil dessen, was im Betriebssystemteil liegt, ist auf den Speicher der Grafikkarte gemappt). Dafür muss Windows mit einem speziellen Schalter gebootet und das Programm mit Support dafür kompiliert werden. Wie das bei TCC und LCC geht, kann ich dir aus dem Stand aber nicht sagen.

    Ansonsten dürfte ein 64-Bit-Compiler helfen, ja.



  • Wutz schrieb:

    CJens schrieb:

    Ich habe Windows Ultimate 64 bit und 32 GB RAM.

    Das hat überhaupt nichts zu sagen, entscheidend ist der Compiler bzw. dessen erzeugtes Programm.

    Na, dann wünsche ich dir viel Spaß dabei, ein 64-Bit-Windows-Programm unter 32-Bit-Windows auszuführen. Oder ein Programm, das 32 GB Speicher braucht, mit weniger. Windows schonmal beim Swappen erlebt?

    Natürlich spielen das Betriebssystem und die vorhandene Menge RAMs eine Rolle. Sie allein reichen nur halt nicht aus.


  • Mod

    seldon schrieb:

    Wenn du in irgendeinem 32-Bit-Programm auf irgendeiner Plattform 4 GB am Stück reserviert kriegst, bin ich echt beeindruckt. Üblicherweise gehen erstmal 1-2 GB des virtuellen Adressraums für das Betriebssystem drauf, und dann gibt es da noch Threadstacks, dedizierte Bereiche für memory mapping und derlei, und wenn man nicht gerade unter Laborbedingungen arbeitet auch noch Dinge anderer Programmteile auf dem Heap. Dessen freie Bereiche nicht an einem Stück liegen müssen.

    Unter Windows sind in 32-Bit-Prozessen per Default 2GB fürs Betriebssystem reserviert, das ist erstmal der größte Posten (darum schmiert das auch bei 2GB Auslastung ab). Es ist möglich, diesen Anteil auf 1 GB zu verringern, wenn du nicht grad viel mit Grafik machst (ein großer Teil dessen, was im Betriebssystemteil liegt, ist auf den Speicher der Grafikkarte gemappt). Dafür muss Windows mit einem speziellen Schalter gebootet und das Programm mit Support dafür kompiliert werden. Wie das bei TCC und LCC geht, kann ich dir aus dem Stand aber nicht sagen.

    Nein. Dem Programm steht sein gesamter Adressraum zur Verfügung, da ist nichts für das Betriebssystem reserviert. Windows reserviert sich 2 GB vom gesamten Arbeitsspeicher, das betrifft den für die einzelnen Prozesse verfügbaren Speicher aber nur indirekt. Außerdem sind die 32-Bit Versionen von Windows künstlich auf 4 GB Gesamtspeicher beschränkt, daher kann man leicht den Eindruck bekommen, dass einem Prozess nur 2GB zur Verfügung stünden. Weil 2GB alles ist, was unter Win32 noch übrig bleibt für Prozesse. Diese werden aber von allen Prozessen geteilt. Wäre mehr Speicher da, könnte jeder Prozess auch mehr benutzen.



  • @ SeppJ:
    Warum empfhiehlst du jedem, nicht umzucasten?

    Manche Compiler erwarten das sogar! Der gcc mault schon rum, wenn ich ein int8_t * nicht auf ein char * umcaste!

    Und wegen so einem umcasten von allokiertem Speicherplatz wird das Programm schon nicht abstürzen.



  • überzeugter Marxist schrieb:

    Warum empfhiehlst du jedem, nicht umzucasten?

    Weil so ein mögliches fehlen von stdlib.h verdeckt wird.

    überzeugter Marxist schrieb:

    Manche Compiler erwarten das sogar! Der gcc mault schon rum, wenn ich ein int8_t * nicht auf ein char * umcaste!

    malloc liefert aber einen void* . Und die sind in C in jeden anderen Zeigertyp konvertierbar. C++-Compiler verlangen den Cast

    überzeugter Marxist schrieb:

    Und wegen so einem umcasten von allokiertem Speicherplatz wird das Programm schon nicht abstürzen.

    Wenn du sonst alles richtig gemacht hast nicht.
    Hier geht es aber um Fehlersuche und darum siehe 1. Antwort.



  • überzeugter Marxist schrieb:

    @ SeppJ:
    Warum empfhiehlst du jedem, nicht umzucasten?

    Manche Compiler erwarten das sogar! Der gcc mault schon rum, wenn ich ein int8_t * nicht auf ein char * umcaste!

    Und wegen so einem umcasten von allokiertem Speicherplatz wird das Programm schon nicht abstürzen.

    void* wurde extra eingeführt damit nicht gecastet werden muss. Denn Casts sollten nur im Ausnahmefall benutzt werden, da sie das Typsystem aushebeln. Das Typsystem ist wichtig weil es viele Fehler findet.

    Ich habe schon gesehen was passieren kann wenn die "Casteritis" um sich greift Zitat: "ich caste alles weil C so Typunsicher ist, deshalb caste ich immer, sonst meckert C weil es den Typ nicht kennt" , "aber irgendwie geht mein Programm nicht" . Es beginnt bei malloc und dann wird plötzlich alles gecastet. Was nicht passt wird passend gecastet!

    char != int8_t



  • SeppJ schrieb:

    Dem Programm steht sein gesamter Adressraum zur Verfügung, da ist nichts für das Betriebssystem reserviert. Windows reserviert sich 2 GB vom gesamten Arbeitsspeicher, das betrifft den für die einzelnen Prozesse verfügbaren Speicher aber nur indirekt.

    Da irrst du dich. Steht übrigens in dem Link über /3GB auch vorne mit dabei. Das ist hier im Detail erklärt. Spoiler: Der Grund ist, dass der Kernel Zugriff auf den Userspace eines Prozesses hat/braucht.

    SeppJ schrieb:

    Außerdem sind die 32-Bit Versionen von Windows künstlich auf 4 GB Gesamtspeicher beschränkt, daher kann man leicht den Eindruck bekommen, dass einem Prozess nur 2GB zur Verfügung stünden. Weil 2GB alles ist, was unter Win32 noch übrig bleibt für Prozesse. Diese werden aber von allen Prozessen geteilt. Wäre mehr Speicher da, könnte jeder Prozess auch mehr benutzen.

    Die künstliche Beschränkung auf 4 GB Phymem (auch mit PAE-Unterstützung) betrifft hauptsächlich die Desktop-Versionen von 32-Bit-Windows; Server-Windows kann da schon seit Windows 2000 mehr, aber sei's drum. Es hat mit dem virtuellen Adressraum wenig zu tun -- Die insgesamt gemappten Pages aller Prozesse können auch dort mehr als 4GB beschreiben, indem eine Swapfile bemüht wird.



  • gary1195 schrieb:

    Ich habe schon gesehen was passieren kann wenn die "Casteritis" um sich greift

    Toll. Ich auch. Ständig.

    gary1195 schrieb:

    Zitat: "ich caste alles weil C so Typunsicher ist, deshalb caste ich immer, sonst meckert C weil es den Typ nicht kennt" , ... Es beginnt bei malloc und dann wird plötzlich alles gecastet. Was nicht passt wird passend gecastet!

    Das ist eine Unsitte aus C++ übernommen, die da ständig rumcasten, weil sie keinen Überblick über ihre Vererbungshierarchie haben bzw. nie hatten; wenn sie denn überhaupt mal Vererbung benutzen.
    In C braucht bzgl. void* bekanntlich überhaupt nicht gecastet zu werden, und es ist noch sehr die Frage (nicht für mich), ob Casting die (Typ)Sicherheit des Programms erhöht.
    Überhaupt sind ausschließliche Zeigercasts in C völlig unnötig, welche mit anschließender sofortiger Dereferenzierung mögen angehen:

    char *x = *(char**)voidp;
    

    Es gibt sogar Fachbücher, die die Notwendigkeit von Casts für die Dokumentation (liebe Kinder, nicht nachmachen) empfehlen:
    http://www.amazon.de/product-reviews/3897212382/ref=cm_cr_pr_hist_1?ie=UTF8&filterBy=addOneStar

    Ich kenne nur einen Anwendungsfall, bei dem in C ein eindimensionaler Zeiger-Cast wirklich notwendig ist, aber den werde ich hier jetzt nicht breittreten.



  • CJens schrieb:

    Achso - brauch ich auch ne 64 Bit Compilerversion von TCC bzs. LCC?

    Die Frage ist auch, brauchst du überhaupt alle Daten gleichzeitig im Speicher?
    Evtl. kannst du dir den 64Bit Eiertanz mit einem Programmumbau ersparen.


  • Mod

    Wutz schrieb:

    Das ist eine Unsitte aus C++ übernommen, die da ständig rumcasten, weil sie keinen Überblick über ihre Vererbungshierarchie haben bzw. nie hatten; wenn sie denn überhaupt mal Vererbung benutzen.

    So ein Quatsch. Das sind in C++ genau so die schlechten Programmierer wie in C. Klingt wie Java in C++, was du beschreibst.

    seldon schrieb:

    SeppJ schrieb:

    Dem Programm steht sein gesamter Adressraum zur Verfügung, da ist nichts für das Betriebssystem reserviert. Windows reserviert sich 2 GB vom gesamten Arbeitsspeicher, das betrifft den für die einzelnen Prozesse verfügbaren Speicher aber nur indirekt.

    Da irrst du dich. Steht übrigens in dem Link über /3GB auch vorne mit dabei. Das ist hier im Detail erklärt. Spoiler: Der Grund ist, dass der Kernel Zugriff auf den Userspace eines Prozesses hat/braucht.

    Entweder reden wir gerade aneinander vorbei oder beide Links bestätigen genau das was ich sage, bis auf das kleine Detail, dass Prozessspeicher wohl auf 2 GB beschränkt ist, nicht 4GB.

    In 32-bit Windows, the total available virtual address space is 2^32 bytes (4 gigabytes). Usually the lower 2 gigabytes are used for user space, and the upper 2 gigabytes are used for system space.

    http://i.msdn.microsoft.com/dynimg/IC535111.png



  • Wenn ich die Betonung mal anders setzen darf:

    In 32-bit Windows, the total available virtual address space is 2^32 bytes (4 gigabytes). Usually the lower 2 gigabytes are used for user space, and the upper 2 gigabytes are used for system space.

    ...dass der virtuelle Adressraum auf einer 32-Bit-Plattform 4 Gigabyte groß ist, ist normal (weil 32-Bit-Zeiger). Das ist auch auf einem 32-Bit-Windows-Server mit 64 GB physikalischem Speicher und PAE so. Unter Windows ist per Default die Hälfte davon für das System reserviert, dem Prozess stehen also noch 2 GB zur Verfügung.

    Das läuft unter Linux übrigens auch nicht anders, nur dass das System da per Default nur 1 GB reserviert. Es wäre auch anders nicht möglich, weil der Kernelcode mit dem Userspace umgehen können muss und es dort ausgesprochen unpraktisch wäre, wenn beispielsweise eine load-Instruction die Daten aus dem Userspace nicht lesen könnte, weil im TLB für die Adresse grad der Systemspeicher steht.



  • SeppJ schrieb:

    So ein Quatsch. Das sind in C++ genau so die schlechten Programmierer wie in C. Klingt wie Java in C++, was du beschreibst.

    Was genauso ein Quatsch ist.

    Herrlich diese Sprachflames 😉


  • Mod

    µ schrieb:

    SeppJ schrieb:

    So ein Quatsch. Das sind in C++ genau so die schlechten Programmierer wie in C. Klingt wie Java in C++, was du beschreibst.

    Was genauso ein Quatsch ist.

    Herrlich diese Sprachflames 😉

    Ich bezog mich auf Wutz' Ansage von Vererbungshierarchien, die so kompliziert sind, dass der Programmierer selber nicht mehr durchblickt. Mag in Java normal sein (habe nicht genug Erfahrung in Java). Aber wenn man jemanden fragt, der das in C++ macht, ist die Rate hier im Forum 100%, dass er von Java kommt.



  • SeppJ schrieb:

    Ich bezog mich auf Wutz' Ansage von Vererbungshierarchien, die so kompliziert sind, dass der Programmierer selber nicht mehr durchblickt. Mag in Java normal sein (habe nicht genug Erfahrung in Java). Aber wenn man jemanden fragt, der das in C++ macht, ist die Rate hier im Forum 100%, dass er von Java kommt.

    Um genau zu sein hat er gesagt, dass ständig gecastet werden muss, weil der Programmierer keinen Überblick mehr hat. Und die Aussage ist eben auch für Java totaler Unsinn.


Anmelden zum Antworten