Problem mit QT (mingw) und calloc / QT Speicherhandling

Alles rund um die Programmierung mit Qt
Antworten
m.mickey
Beiträge: 27
Registriert: 10. Januar 2010 23:01

Problem mit QT (mingw) und calloc / QT Speicherhandling

Beitrag von m.mickey »

Hallo,
ich habe ein Problem wenn ich versuche innerhalb einer QT Anwendung (unter mingw) mehr als 1.5 GB Speicher bereitzustellen. In der Beispielanwendung, wird Speicher über

Code: Alles auswählen

char (*Test1) = (char *) calloc(500*1024*1024,1);
memset(Test1, '\0', 500*1024*1024);

reserviert. Es läuft unter mingw solange der komplette Speicher weniger als ca 1.5 GB beträgt. Dann kommt ein segfault. Unter Linux komme ich auch bis 1.9 GB mit dem gleichen Programm.
Dies ist nur ein Beispielprogramm, deswegen fange ich den Speicher nicht auf und lösche ihn am Ende nicht. (In meinem Anwendungsfall brauche ich auch über 1.5 GB gleichzeitig.)
Nachdem es unter Linux problemlos läuft habe ich zuerst auf einen Bug von QT und mingw getippt, aber das wurde von QT Seite verneint.
Getestet mit mehreren QT Versionen und verschiedenen Mingw, zuletzt mit QT 4.7.0 beta1 unter TDM 4.5.
Was mache ich falsch? Kann mir bitte jemand helfen?

Viele Grüße mickey
Dateianhänge
menus.7z
(1.91 KiB) 217-mal heruntergeladen
Zuletzt geändert von m.mickey am 10. Juni 2010 14:26, insgesamt 1-mal geändert.
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Warum sollte QT da eine Rolle spielen, du rufst ja keine QT-Funktion zur Speichereservierung auf?
m.mickey
Beiträge: 27
Registriert: 10. Januar 2010 23:01

Beitrag von m.mickey »

Weil der gleiche calloc Befehl ohne QT, also in einem einfachen Konsolenprogramm, unter mingw funktioniert...

Viele Grüße mickey
m.mickey
Beiträge: 27
Registriert: 10. Januar 2010 23:01

Beitrag von m.mickey »

Hier nochmal das Vergleichsprogramm ohne QT. So kann ich problemlos 1.8 GB reservieren, auch unter mingw.

Code: Alles auswählen

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cmath>

using namespace std;

int main(){

  char (*Test1) = (char *) calloc(500*1024*1024,1);
  memset(Test1, '\0', 500*1024*1024);
  cout << "500 MB" << endl;
  cin.get();

  char (*Test2) = (char *) calloc(500*1024*1024,1);
  memset(Test2, '\0', 500*1024*1024);
  cout << "1000 MB" << endl;
  cin.get();

  char (*Test3) = (char *) calloc(500*1024*1024,1);
  memset(Test3, '\0', 500*1024*1024);
  cout << "1500 MB" << endl;
  cin.get();

  char (*Test4) = (char *) calloc(300*1024*1024,1);
  memset(Test4, '\0', 300*1024*1024);
  cout << "1800 MB" << endl;
  cin.get();

  free(Test1);
  free(Test2);
  free(Test3);
  free(Test4);
  cin.get();

  return 0;
}
viele Grüße mickey
kater
Beiträge: 306
Registriert: 29. Dezember 2009 01:13
Wohnort: Darmstadt

Beitrag von kater »

Damn, jetzt hab ich soviel Text geschrieben und weg war er. Ok hier die Kurzfassung.

- Du kannst 100GB reservieren ohne Fehler aber nicht nutzen. Die Speicherverwaltung von Linux ist da komisch.

- Es kann Probleme geben viel Speicher am Stück zu nutzen. Z.B. 200MB nicht, aber dafür zwei mal 100MB Stücke.

- Du hast in deinem Beispiel ca. 5GB reserviert und mit 0 belegt ohne Fehler. Angeblich. Du hast aber nicht auf den Speicher lesen zugeriffen, das gäbe dann ein Fehler.

malloc/calloc oder memset sagen wieviel Speicher wirklich zu Verfügung steht. Gug mal in die manpage. Dann baue eine Fehlerbehandlung ein und dann siehst du wieviel MB du am Stück wirklich nutzen kannst.
Curtis Newton
Beiträge: 122
Registriert: 11. Juni 2008 18:39

Beitrag von Curtis Newton »

m.mickey hat geschrieben:Weil der gleiche calloc Befehl ohne QT, also in einem einfachen Konsolenprogramm, unter mingw funktioniert...

Viele Grüße mickey
Die dlls müssen ja irgendwo eingeblendet werden. Und das werden sie vornehmlich in "hohen" Speicherbereichen. Wenn Du Dir Speicher mit m/calloc holst, muss dieser "am Stück" vorliegen. Bevor die dlls geladen werden, mag noch ein großer Speicherbereich frei sein. Danach nicht mehr.

Der segfault kommt aber eher daher, dass Du memset benutzt, ohne die Rückgabe von calloc zu testen. Außerdem, warum calloc, wenn Du eh memset benutzt...

C.
m.mickey
Beiträge: 27
Registriert: 10. Januar 2010 23:01

Beitrag von m.mickey »

Danke für eure Antworten.

Ich reserviere insgesamt 1800 MB in 500 + 500 + 500 + 300 Schritten.

Der memset Schritt hier ist nur zum Testen des Zugriffs, im Anwendungsfall wird nach dem calloc das Feld mit Daten gefüllt...

Also besteht das Problem also darin, dass die QT dll's den "oberen" Bereich des Speichers segmentieren und dadurch keine großen Blöcke mehr reserviert werden können. Und nach fehlgeschagener Reservierung dann natürlich der segfault beim Zugriff...

Gibt es eine Möglichkeit den Speicher aufzuräumen, also die dlls an den Rand zu schieben? Weil das Programm hat insgesamt ja nicht mal 1.5 GB also sollte ja noch Speicher zur verfügung stehen, bevor die 2GB Grenze kommt...

Viele Grüße mickey
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

@kater
Du kannst 100GB reservieren ohne Fehler aber nicht nutzen. Die Speicherverwaltung von Linux ist da komisch.
Sicher ? Das wuerd ja bedeuten das sich der gcc ned an den ISO C Standard haelt. Dort wird vorgeschrieben, dass calloc nur einen ungleich NULL Pointer zurueckgeben darf, wenn der Aufruf erfolgreich(also aller speicher allokiert wurde) durchging.

Also nen calloc oder malloc iss fuer das betriebssystem nen gleichzeitiges nutzen, weil das BS ned mitbekommt ob dein programm den speicher auch wirklich nutzt.

Und wie sollt nen Programm wissen, ob es denn allocierten speicherbereich belegen darf ohne nen Signal zu kassieren (Anmerkung, C kann keine Exceptions, also calloc und malloc werden dir nie eine werfen) ... wenn es keinen fehlercode zurueckbekommt.


@m.mickey

das Du mit calloc 1,5 GByte reservieren willst, iss nur die halbe Wahrheit.
Die ganze Wahrheit iss, das du 1,5 GByte am Steuck allokieren willst.

Und glaub das haengt ziemlich vom Speicherausbau, der Verwaltung deines BS und dem momentanen systemzustand ab !

unter windows 7 64 bit krieg ich mit der 32bit runtime (vc project kompiliert als 32 bit app) auch nur unwesentlich mehr als 1,5 GB hin am stueck (mit new) obwohl 8GB Speicherausbau.
unter 64 bit werdens dann locker mehr :-)

Problem fuer windows iss, nen 32 bit programm kann nie mehr als 2 (nein, nicht 4) GB Speicher insgesammt allokieren. Mehr speicherseiten bekommt es nicht. da sind dann aber auch noch andere dinge drinne ... nicht nur der dynamische speicher. Stack, CodeSegment, Shared memory, filediskreptoren, eingeblendeter speicher von benutzten dlls.

Wenn man die bissi ungeschickt organisiert, kann schon 500MB vom max Adressraum weg sein ... kann sein, das das Linux geschickter macht.

Aber beantworte uns doch mal bitte:
Warum brauchst du unter c++ +1Gb speicher am stueck ?
selbst bei gestandenen Embedded / C-Programmierern werden bei solchen Groessen die Fragezeichen um den kopf schwirren ...

Kannst das ned in mehrere Bloecke aufteilen ?
warum so viel ueberhaupt in den speicher ?
Kannst du nicht nen Temp file nehmen und nur teile davon in den Speicher einblenden (memory Mapped IO) ?

Ciao ...
m.mickey
Beiträge: 27
Registriert: 10. Januar 2010 23:01

Beitrag von m.mickey »

Danke für deine ausführliche Antwort.

Ich brauche den Speicher nicht am Stück, das war nur für dieses Beispiel und zum Testen. Es handelt sich um eine Bildbearbeitung, die immer komplette Bilder berechnet, nicht nur Ausschnitte (mit Absicht). Und da es sehr viele Filter gibt sind einige Zwischenspeicher vorhanden.
Also sagen wir ein 14-18 MP Photo mit drei Kanälen und float sollten die größten Blöcke sein. (Klar wenn jemand ne 40 MP Kamera hat wirds bitter, aber ich hoff mal der hat dann 64bit...)
Also 18.000.000*3*4 sind die durchschnittlich größten Stücke (wenn ich gerade nichts übersehe).

Ich bin ja schon mal beruhigt, dass es kein Bug ist, sondern nur unachtsam programmiert...

Zu deinem memory mapped IO, hättest du dazu ein (einfaches) Tutorial oder so (kann auch Englisch oder ein Buch sein). Muss aber portabel sein, Linux, Mac, Win.

Viele Grüße mickey
kater
Beiträge: 306
Registriert: 29. Dezember 2009 01:13
Wohnort: Darmstadt

Beitrag von kater »

@RHBaum ja ist ein Bug. Aber nicht vom gcc, da der den Code ja nur kompiliert aber nicht feststellen kann wieviel GB im System sind.

Im Manpage zu malloc steht was ich meine. Ich poste es hier mal
BUGS
By default, Linux follows an optimistic memory allocation strategy.
This means that when
malloc() returns non-NULL there is no guarantee that the memory really is available.
This
is a really bad bug. In case it turns out that the system is out of memory, one or more
processes will be killed by the infamous OOM killer. In case Linux is employed under cir-
cumstances where it would be less desirable to suddenly lose some randomly picked pro-
cesses, and moreover the kernel version is sufficiently recent, one can switch off this
overcommitting behavior using a command like:

# echo 2 > /proc/sys/vm/overcommit_memory

See also the kernel Documentation directory, files vm/overcommit-accounting and
sysctl/vm.txt.
Antworten