Speichermangel bei mehr als 5000 BMPs!!



  • Hallo zusammen,
    hier hab ich mal 'ne harte Nuß! Ich habe ein Programm geschrieben, mit dem man einen Font erzeugen (kein TrueType) kann und die Pixel der Zeichen des Fonts bearbeiten kann. Den kompletten Font habe ich in einer extra View mit Hilfe von GDI Bitmaps für jedes Zeichen als Liste dargestellt (CObList). Ein Font hatte bisher max 256 Zeichen (ASCII) und somit 256 Bitmaps, die ich auf den Heap gelegt habe.

    Soweit so gut. Nun soll ich auf Unicode umstellen, damit asiatische Zeichen auch in die Fonts aufgenommen werden können. Da dies aber bedeutet, daß ich nunmehr mehrere tausend Zeichen aufnehmen können muß, benötige ich entsprechend viele Bitmaps. Doch ab 4900 Bitmaps ist schluß!!!

    Ich hab schon mehrere Ansätze versucht, um dieses Problem zu umgehen. Beispielsweise habe ich versucht, nur soviele Bitmaps zu erzeugen, wie auch tatsächlich angezeigt werden und diese dann zu verschieben und dynamisch mit dem entsprechenden Inhalt zu füllen, je nachdem wohin ich scrolle. Aber einerseits ist die Verwaltung extrem kompliziert (aber möglich) und andererseits scheitert diese Lösung aus Performance Gründen aus, da das dynamische Füllen während dem scrollen zu lange dauert. Auch diverse Paging Techniken habe ich ausprobiert (immer nur ganze Blöcke werden beim Scrollen geladen), aber auch das scheitert an der Performance.

    Jetzt weiß ich nicht mehr weiter!!! Gibt es eine Möglichkeit, mit der Auslagerungsdatei zu arbeiten? Oder hat jemand eine andere Idee, wie ich dieses Problem lösen könnte?

    Für eure Ideen bedanke ich mich jetzt schon herzlich!!

    Viele Grüße
    RG_Basser



  • Wie gross ist ein Bild?
    Braucht du True Color?

    Ich komme bei einem .bmp File mit 300300 sw Pixeln auf 12062 Byte
    und somit bei 65536 Bildern auf 754 MB
    bei 200
    200 auf 354 MB

    Die Zahl der Bilder berechnete ich als absolute Maximalzahl für Unicode

    Mein Verdacht ist das du dein RAM und deine Auslagerungsdatei überforderst und deshalb der Fehler kommt

    Hoffentlich habe ich Recht

    😃



  • Ändere das Design deiner Anwendung. Niemand will sich durch 50000 Bitmaps scrollen.



  • @Unregistrierter
    Recht hast du.

    Auf der anderen Seite hilft es ihm wahrscheinlich die Fehler in seine Konzepten zu erkennen und erst den Memoryverbrauch zu planen bevor man ans kodieren geht.

    Vergleichbare Probleme können auch bei 100 Bildern auftreten wenn sie Entsprechend groß sind.

    Was muss man tun wenn die Applikation nicht nur auf einem Superrechener
    mit 1GB RAM und 2GB Auslagerungsdatei sondern auch mit 128 MB und 256 MB Auslagerungsdatei laufen soll.

    PaintshopPro hat mich auch schonmal mit ähnlichem beglückt allerdings bei 3 gescannten Bildern (900 DPI)



  • Hmmm - also keine Schriftart die du mit TextOut ausgeben könntest?

    Du könntest die Bitmaps komprimiert speichern, z.B. als PNG. Oder in einem zip Format. Mit zip sparst du über 90% an Speicher. Mit der Performance sollte das dann auch noch klappen.



  • @PAD
    Zu deiner ersten Frage: Ich verwende 50x90 Pixel große CBitmaps (sw) und ich bestätige deinen Verdacht, insofern der Heap bei der 4900er Grenze voll ist.

    PAD schrieb:

    Auf der anderen Seite hilft es ihm wahrscheinlich die Fehler in seine Konzepten zu erkennen und erst den Memoryverbrauch zu planen bevor man ans kodieren geht.

    Prinzipiell hast du hierzu völlig recht, doch leider ist zwischen der ursprünglichen Vorgabe von 255 Zeichen bei ASCII und über 4 Millionen (2³²) Zeichen bei UNICODE ein himmelweiter Unterschied, den ich nun wirklich nicht vorhersehen konnte. Und selbst wenn ich diesen Umstand berücksichtigt hätte, wüßte ich immer noch nicht, wie ich dieses Problem lösen soll. Genau deshalb hatte ich ja gehofft, hier auf die eine oder andere Idee zu kommen! Geändert ist meine Anwendung schnell, denn gottseidank habe ich vorausgeplant und eine Änderung wäre also durchaus noch möglich 😉 Jedenfalls trotzdem Danke für deine Mühe 🙂

    @Unregistrierter

    Anonymous schrieb:

    ... Niemand will sich durch 50000 Bitmaps scrollen.

    Wer sagt, daß sich niemand durch 50000 Bilder scrollen will, wenn genau das eine Vorgabe ist? Und wenn schon eine so konkrete Antwort wie

    Anonymous schrieb:

    Ändere das Design deiner Anwendung..

    , dann hast du bestimmt auch eine Idee wie?! Aber warum antworte ich eigentlich jemandem unregistrierten???



  • Man könnte doch ein grosses Bitmap anlegen. Selbst, wenn alle Zeichen des UNICODE-Zeichensatzes (2^16) belegt sind, was wohl so gut wie nie der Fall sein wird, wäre das Bitmap nach meiner Rechnung (50*90*65535/8) gerade mal 36MB gross, was für diese Anzahl Zeichen IMHO durchaus zu verkraften ist.



  • Bei der größe der Bitmaps 782 Bytes und 65536 unterschiedlichen Bitmaps ergibt
    sich ein Speicherbedarf von 48MB.

    Wenn es sich um Chinesische Zeichensätze handelt, so ist der grundwortschatz ca 30000 Zeichen und bei hoher Bildung um die 10.000 Zeichen.
    Somit würde ich von 16.000 Bildern ausgehen mit 12 MB Speicherplatz.

    Wenn da der Heap platzt gibt es glaube ich Möglichkeiten entweder den Heap zu vergrößeren oder aber einen prvaten Heap anzulegen
    😃
    Ich habe selbst keine Erfahrung damit aber schaue in der Hilfe (/MSDN) nach
    unter

    Platform SDK: Memory Management
    Virtual Memory Functions

    ➡ Hier eine Auschnitt aus "Managing Heap Memory in Win32"
    zu finden in VC Hilfe such nach den Stück in '"'

    ⚠ Managing the Default Heap

    Both default and dynamic heaps have a specific amount of reserved and committed memory regions associated with them, but they behave differently with respect to these limits. The default heap's reserved and committed memory region sizes are designated when the application is linked. Each application carries this information about itself within its executable image information. You can view this information by dumping header information for the executable image. For example, type the following command at a Windows NT command prompt (PWALK.EXE is used here to complete the example; you will need to substitute your own path and executable file):

    link32 -dump -headers d:\samples\walker\pwalk.exe

    ...
    OPTIONAL HEADER VALUES
    10B magic #
    2.29 linker version
    B000 size of code
    1E800 size of initialized data
    600 size of uninitialized data
    18470 address of entry point
    10000 base of code
    20000 base of data
    ----- new -----
    400000 image base
    10000 section alignment
    200 file alignment
    2 subsystem (Windows GUI)
    0.B operating system version
    1.0 image version
    3.A subsystem version
    C0000 size of image
    400 size of headers
    0 checksum
    10000 size of stack reserve
    1000 size of stack commit
    10000 size of heap reserve
    1000 size of heap commit
    ...

    The last two entries are hexadecimal values specifying the amount of reserved and committed space initially needed by the application.

    There are two ways to tell the linker what to use for these values. You can link your application with a module definition file and include a statement in the file like the following:

    HEAPSIZE 0x10000 0x1000

    Or you can directly inform the linker by using the /HEAP linker switch, as in:

    /HEAP: 0x10000, 0x1000

    In both examples, the heap is specified to initially have 0x10000 (64K) bytes reserved address space and 0x1000 (4K) bytes committed memory. If you fail to indicate the heap size in either method, the linker uses the default values of 0x100000 (1 MB) reserved address space and 0x1000 (4K) committed memory.

    The linker accepts almost any value for heap reserve space, because the application loader ensures that the application will meet certain minimum requirements during the load process. In other words, you can link an application with an initial heap value of 1 page reserved address space. The linker doesn't perform any data validation; it simply marks the executable with the given value. Yet, since the minimum range of address space that can be reserved is 16 pages (64K), the loader compensates by reserving 16 pages for the application heap at load time.

    As indicated above, options exist that indicate how much memory should initially be committed for an application's default heap. The problem is they don't seem to work yet. The linker for the second beta release of Windows NT marks all executable applications with 0x1000 (4K) initial committed memory for the default heap size, regardless of the value indicated as an option. Yet this is not that big a deal because it actually may be better for an application to commit as it needs to, rather than to commit memory that is not being used.



  • Ach ja stimmt. 🙄 Ich bin ja von Farb Bitmaps ausgegangen - man braucht ja nur schwarz/weiss. Gut dann brauch man nicht komprimieren.



  • @All
    Erstmal Danke für eure Ideen. Ich denke, da ist der eine oder andere Ansatz dabei, mit dem ich evtl. was anfangen kann 🙂

    @RenéG
    Die Idee mit dem großen Bitmap ist nicht schlecht 🙂 Da ich die Bitmaps jedoch im Heap halte, sind glaube ich 36 MB (oder 48, wie Pad geschrieben hat) doch etwas zu viel, oder nicht 😕
    Wenn ich jedoch eine Anpassung des Heaps vornehme, wie Pad vorgeschlagen hat, könnte es evtl funktionieren 😃

    @PAD
    Vielen herzlichen Dank für den Hinweis mit dem Heap und die entsprechende Quelle, das hilft mir wirklich sehr 😃 😃
    Ich werd jetzt mal ein weilchen die Quellen lesen und schauen, was dabei rauskommt. Wenn's was neues gibt (in Bezug meines Problems), melde ich mich wieder 🕶

    P.S. Wie bekommt ihr eigentlich die Größen der Bitmaps? Errechnet oder ausprobiert?

    Gruß
    RG_Basser



  • :p Bin stinkfaul, habe mit psp eine Bitmap der Größe in S/W angelegt, gespeichert Die Grösse mit dem Totalcommander angeschaut und dann mit Anzahl der Bilder multipliziert. :p

    Wäre am Ergebnis der Heap Sachen interessiert, irgendwie habe ich das Gefühl in der nächsten Zeit wir mich da auch was ärgern. 😕



  • Wer sagt, daß sich niemand durch 50000 Bilder scrollen will, wenn genau das eine Vorgabe ist? Und wenn schon eine so konkrete Antwort wie Anonymous schrieb:
    Ändere das Design deiner Anwendung..
    , dann hast du bestimmt auch eine Idee wie?! Aber warum antworte ich eigentlich jemandem unregistrierten???

    😃 😃 😃

    Mal ehrlich, wer durch 50000 Eintraege Scrollen will, soll bestraft werden 🙂 durch ladezeiten beim scrollen 🙂

    Wie speicherst du deine Bitmaps, liegen die wirklich als BMP in nem Verzeichniss, oder in ner DB ?

    Bzw wie bekommst die Zurdnung hin ? Zeichen -> Bitmap ...

    Ansatz ist je nach den gegebenheiten unterschiedlich ...

    Scrollen ? Du meinst, DU hast ne Listbox aehnliches auswahlfeld ? wo der benutzer den zeichencode und die Bitmap sieht ....

    Oder du Hast nen dialog wo der nutzer nur den zeichencode eingibt und das zeichen wird daraufhin dargestellt ?

    Oder Gar ne Datei aus Zeichencodes (TextDatei) die auf nen GDI per bitmaps mit deinen Fonts dargestellt werden soll ? (ist eigentlich der Sinn von so Font Sachen )

    WIrst nicht drumherumkommen, DIe sachen dynamisch zu laden, also bei bedarf und ned alles im speicher halten ....

    WIllst scrollen, wuerd ich ne cached Liste anlegen, wo max zb. nur 100 elemente im speicher stehen und wenn weitere geladen werden (muessen) aeltere einfach wieder aus dem speicher werfen ....

    Wenn die bilder alle die selben Farbpaletten haben, dann vielleicht in ne temp zwischendatei laden, wo nur einmal die farbpalette drin ist ... wie ReneG vielleicht vorgeschlagen hat, ne grosse Bitmap wo die Teilbitmaps in nem koordinatensystem zu nem grossen bild zusammen gerastert sind.

    Bei 50000 bitmaps in der liste wird er dann halt mit etwas wartezeit beim scrollen belohnt 🙂 Aber programmieren muesstest das per hand ...

    Ciao ...



  • wenn man sich eine spalte bilder haelt.
    (32 schriftzeichen uebereinader) kann man die gemuetlich in einem std::vector<byte[90][50*32]> speichern und bei jedem scroll schreibt man einfach diesen vector in ne bitmap.



  • @RHBaum
    Eigentlich hast du recht, mit dem bestrafen 😃 Aber Spaß beiseite. Das Prinzip funktioniert folgendermaßen:

    In meiner MDI Anwendung halte ich im Dokument alle Zeichen des Fonts als CObListe. Ein Zeichen ist eigentlich nichts anderes als ein 2 dimensionales Array [50][90], in dem die Werte schwarz oder weiß gespeichert sind (schwarz für ein gesetztes Pixel).
    Damit ich nun alle Zeichen in einem extra Fenster anzeigen kann, habe ich eine CObListe von genausovielen Bitmaps erstellt, wie Zeichen im Font vorhanden sind. Außerdem habe ich dazu passend auch eine CObListe von Gerätekontexten erstellt, damit die Bitmaps überhaupt auf dem Bildschirm darstellbar sind. Beim Erzeugen werden die Bitmaps Pixel für Pixel gefüllt. Dargestellt werden diese Bitmaps tabellarisch, d.h. 16 Zeilen und x Spalten. Das ganze sieht wie folgt aus:

    // Bitmap Liste
    CObList m_BmpObjList;	
    CBitmap* m_pBmpList;
    
    // Liste Speicherkontext
    CObList m_CDCObjList;	
    CDC* m_pCDCList;
    
    CClientDC dcScreen(this);
    
    // Anlegen von k Bitmaps und Speicherkontexten in der Liste
    for(int k=0; k<nSum; k++)
    {
    	m_pBmpList = new CBitmap;// Anlegen eines CBitmap-Objektes
    	m_BmpObjList.AddTail(m_pBmpList); // Einfügen in die Bmp-Liste
        m_pBmpList->CreateCompatibleBitmap(&dcScreen,50,90);
    
    	// Speicherkontext
    	m_pCDCList = new CDC;
    	m_CDCObjList.AddTail(m_pCDCList);
    	m_pCDCList->CreateCompatibleDC(&dcScreen);
    }
    

    Da jedes Bitmap in der Liste der gleichen Position meiner Zeichenliste entspricht, errechne ich über

    pDC->GetClipBox()
    

    und durch die Spalten und Zeilen die Zeichen, die nur beim Scrollen dargestellt werden sollen und übergebe die errechneten Indexwerte meiner Funktion

    CFontView::DrawFont(ZeichenNr)
    

    , welche über den Wert 'ZeichenNr' das entsprechende Bitmap lädt und dann

    pDC->StretchBlt(....m_pCDCList...);
    

    aufruft, womit das Bmp auf den Bildschirm projiziert wird.

    Ich hoffe ich konnte dir (und natürlich auch den anderen) den Ablauf etwas besser erläutern 🙂

    Gruß


Anmelden zum Antworten