Matze: wie diesen Fatal Error abfangen?

Hallo!

Ich habe gerade versucht ein Bild zu manipulieren.
Um Fehler zu finden, habe ich ein jpeg mit 5000x5000px und 72px/Zoll erstellt.

Das Script bricht dabei mit einem Fatal Error bei imagecreatefromjpeg() ab:
Fatal error: Allowed memory size of ... bytes exhausted (tried to allocate ... bytes) in ...

Nach ein bisschen rumgoogeln habe ich herausgefunden, dass die Bilder wohl Pixel für Pixel in den Speicher gelesen werden.
Es spielen also offenbar nicht nur die Ausmaße von 5000x5000px, sondern auch die Auflösung eine Rolle.

Meine Frage wäre, wie ich den Fehler abfangen kann.
Da er im Zusammenspiel mit dem Speicher steht, dürfte der max-Wert für meine Bilder ja überall verschieden sein, oder?

Dank und Gruß, Matze

  1. Nach ein bisschen rumgoogeln habe ich herausgefunden, dass die Bilder wohl Pixel für Pixel in den Speicher gelesen werden.
    Es spielen also offenbar nicht nur die Ausmaße von 5000x5000px, sondern auch die Auflösung eine Rolle.

    Das _ist- die Auflösung ;)

    Meine Frage wäre, wie ich den Fehler abfangen kann.

    http://php.net/manual/en/book.errorfunc.php

    Da er im Zusammenspiel mit dem Speicher steht, dürfte der max-Wert für meine Bilder ja überall verschieden sein, oder?

    Der Speicherverbrauch hängt von der Auflösung und der Farbtiefe ab.

    Anzahl der Bildpunkte horizontal x Anzahl der Bildpunkte vertikal x Farbtiefe = Anzahl der benötigten Bits im RAM

    z.B. ein 24 Bit JPG mit 5.000 x 5.000 Pixel benötigt 600.000.000 Bit. also 75.000.000 Byte (75 MB bzw. 71,5 MiB).

    1. Hallo suit!

      Meine Frage wäre, wie ich den Fehler abfangen kann.

      http://php.net/manual/en/book.errorfunc.php

      Danke, aber kannst du mich bitte noch einen Link tiefer schicken?
      Oder bin ich bei error_get_last richtig?

      Der Speicherverbrauch hängt von der Auflösung und der Farbtiefe ab.[...]

      Danke für die Erklärung!

      Grüße, Matze

      1. Danke, aber kannst du mich bitte noch einen Link tiefer schicken?
        Oder bin ich bei error_get_last richtig?

        Eine einfache Möglichkeit ist mit @ gegeben - da kannst du ggf. ansetzen.

        1. Eine einfache Möglichkeit ist mit @ gegeben - da kannst du ggf. ansetzen.

          Kann ich leider nicht, weil das Script trotzdem stirbt :(
          Ich hab ja ein @ davor: $result = @imagecreatefrom...
          Trotzdem stirbt das Script genau an der Stelle.

          1. http://www.cix-blog.de/PHP-GDlib-und-der-Speicherbedarf-169-2008.html

            Du könntest also vorher den Speicherbedarf errechnen und entsprechend reagieren.

  2. Hallo Matze,

    Fatal error: Allowed memory size of ... bytes exhausted (tried to allocate ... bytes) in ...
    Meine Frage wäre, wie ich den Fehler abfangen kann.

    ein Fatal Error lässt sich leider nicht auffangen. Das Mag suit mit seinem Posting zwar anders sehen, ist aber Tatsache. Das einzige, was Du machen kannst, ist zu bestimmen, ab welchen Dimensionen es regelmäßig zu Speicherlimitüberschreitungen kommt. Dazu kannst Du memory_get_usage() nutzten.
     Anhand der so gewonnenen Richtwerte, kannst Du dann Dein Script selbst abbrechen.

    Gruß aus Berlin!
    eddi

    1. ein Fatal Error lässt sich leider nicht auffangen. Das Mag suit mit seinem Posting zwar anders sehen, ist aber Tatsache.

      Da hast du natürlich recht, mein Fehler.

    2. Hey eddi!

      ein Fatal Error lässt sich leider nicht auffangen. Das Mag suit mit seinem Posting zwar anders sehen, ist aber Tatsache. Das einzige, was Du machen kannst, ist zu bestimmen, ab welchen Dimensionen es regelmäßig zu Speicherlimitüberschreitungen kommt. Dazu kannst Du memory_get_usage() nutzten.
      Anhand der so gewonnenen Richtwerte, kannst Du dann Dein Script selbst abbrechen.

      Oh, danke!
      Also muss ich aus den Werten von getimagesize() den Speicherplatz, nach suits Beispiel, berechnen und prüfen ob der den Wert von memory_get_usage() nicht überschreitet? Bzw. etwas Tolleranz schaffen? Wenn ja, wieviel wär angemessen?

      Danke und Grüße, Matze

      1. Also muss ich aus den Werten von getimagesize() den Speicherplatz, nach suits Beispiel, berechnen und prüfen ob der den Wert von memory_get_usage() nicht überschreitet?

        Schlauer Plan ;) bedenke allerdings die MB != MiB-Problematik. Ich kann auf den Sprung nicht sagen, ob PHP korrekt mit der Basis 1.000 (10^3) für die SI-Vorsätze rechnet oder fälschlicherweise mit 1.024 (2^10) rechnet und trotzdem SI-Präfixe verwendet.

        Bzw. etwas Tolleranz schaffen? Wenn ja, wieviel wär angemessen?

        Das kommt drauf an, wieviel dein restliches Script sonst noch benötigt. Harte Nuss, die ich auf den Sprung nicht beantworten kann.

        1. Schlauer Plan ;)

          Ja, manchmal bin ich ein Fuchs *öähm.. ja

          bedenke allerdings die MB != MiB-Problematik.

          Wow, mit was alles ich mich auf einmal beschäftigen muss.
          Das Problem kannte ich bislang nicht einmal.
          Ich dachte alle Systeme könnten korrekt von Bits bis nach TB umrechnen -.-

          Du zeigst mir da Problem von denen ich gar nicht wusste, dass sie existieren.

          Bzw. etwas Tolleranz schaffen? Wenn ja, wieviel wär angemessen?

          Das kommt drauf an, wieviel dein restliches Script sonst noch benötigt. Harte Nuss, die ich auf den Sprung nicht beantworten kann.

          Viel passiert da nicht mehr.
          An der Stelle mit dem Fehler wird ein Bild gespeichert, wenn das funktioniert hat kommt noch eine Bestätigung.
          Wenn das nicht funktioniert hat, wird ein Eintrag aus einer MySQL-Tabelle gelöscht, das wars.

          Wäre es eine gute Idee, die Hälfte des zur Verfügung stehenden Speichers zu "nutzen" oder ist das schnell zu wenig bzw. ist die Hälfte, die für übrige Vorgänge "reserviert" wurde, zu groß bemessen?

          Danke und Grüße, Matze

          1. Ich dachte alle Systeme könnten korrekt von Bits bis nach TB umrechnen -.-

            Ja, das denken viele - enttäuscht sind dann besonders jene, die sich eine 1-TB-Festplatte kaufen - die entsprechend der Verwendung des SI-Präfix korrekt bemessen ist, Windows aber sagt es wären nur 0,93 TB drauf verfügbar obwohl damit eigentlich 0,93 TiB gemeint wären ;)

            Wäre es eine gute Idee, die Hälfte des zur Verfügung stehenden Speichers zu "nutzen" oder ist das schnell zu wenig bzw. ist die Hälfte, die für übrige Vorgänge "reserviert" wurde, zu groß bemessen?

            Die Hälfte ist sicher übertrieben - 75 % ist sicher auch ok, ggf. auch 90 % - musst du ausprobieren.

          2. Hallo,

            bedenke allerdings die MB != MiB-Problematik.
            Wow, mit was alles ich mich auf einmal beschäftigen muss.

            musst du nicht. Denn wie man im Manual zu memory_get_usage() nachlesen kann, gibt die Funktion den belegten Speicher in Bytes zurück. Die 1024/1000-Problematik ist hier also außen vor.

            Ich dachte alle Systeme könnten korrekt von Bits bis nach TB umrechnen -.-

            Können sie. Nur ist es bei den Programmierern jahrzehntelange Tradition, nicht die Anzahl 1000, sondern 1024 als "1k" zu bezeichnen, denn 1024 ist eine Zweierpotenz und lässt sich daher leichter verarbeiten; und die Werte sind ja hinreichend ähnlich.
            Da sich mit zunehmenden Speichermengen der Fehler von ursprünglich 2.4% potenziert, wird er in manchen Fällen offensichtlich.

            Die ersten, die mit der Konvention "1k=1024" bewusst gebrochen hatten, waren die Festplattenhersteller. Denn wenn das kB etwas größer ist, werden die Zahlen, die die Gesamtkapazität angeben, etwas kleiner. Das ist nicht verkaufsfördernd. So wurden dann teilweise 120MB-Festplatten (ja, das war Anfang der 90er Jahre noch üppig!) als 125MB-Modelle angepriesen, und man hatte zumindest im Werbeprospekt einen kleinen Vorsprung vor Konkurrenten, die noch die traditionellen MB verwendeten.

            Heute sind es mehr die auf formale Korrektheit abfahrenden Theoretiker, die darauf bestehen, richtige SI-Präfixe zu verwenden. Das sind dann ungefähr dieselben Leute, die auch fordern, dass Monitorgrößen in cm statt in Zoll anzugeben sind, so dass die Kunden dann fragen: "Äh, 55cm[*] - wieviel Zoll sind denn das?"
            Oder beim Autohändler.
            Kunde:   Wieviel PS hat denn der Wagen?
            Händler: Steht doch da: 88kW.
            Kunde:   Ja, aber wieviel PS sind das?

            Dadurch, dass man also so aufs Korinthenkacken besteht, schafft man Probleme, wo eigentlich gar keine sind.

            Ciao,
             Martin

            [*] Wobei ich die cm hier für einen Griff ins Klo halte; fast überall in der Technik wird in Meter oder Millimeter gemessen, Zentimeter sind völlig unüblich.

            --
            Der Klügere gibt solange nach, bis er der Dumme ist.
            1. musst du nicht. Denn wie man im Manual zu memory_get_usage() nachlesen kann, gibt die Funktion den belegten Speicher in Bytes zurück. Die 1024/1000-Problematik ist hier also außen vor.

              memory_limit halt als default Wert "128M" - memory_limit - memory_get_usage() = freier Speicher.

              Die ersten, die mit der Konvention "1k=1024" bewusst gebrochen hatten, waren die Festplattenhersteller.

              Nein, die Diskettenhersteller ;) eine 1.44"-Diskette rechnet "ganz anders" ;) solch eine hat 1,40 MiB (lt. IEC), 1,47 MB (lt. SI), 1,40 MB (lt. Windows bzw. "traditionell") und 1,44 MB (lt. Formfaktor).

              Festplatten- und Solid-State-Speicherhersteller haben sich immer 1:1 an SI-Präfixe gehalten.

              RAM-Hersteller (bzw. die JEDEC) nutzen hingegen SI-Präfixe zur Basis 1024, geben aber in deren Empfehlungen an, dass das eine dämliche Idee ist, aber eben "Formfaktorenartige" Bezeichnungen sind.

              Eine 3,5"-Festplatte ist übrigens exakt 100 mm breit - das ist ein gutes Stück mehr als 3,5 Zoll, eine 3,5"-Floppy ist etwa 3,54 Zoll breit (90 mm).

              Es war auch mal Tradition dass es gut 10 verschiedene Defintionen für hp (Horsepower) gab und einen Rattenschwanz für "Zoll" - Zeit das ordentlich zu machen.

              Denn wenn das kB etwas größer ist, werden die Zahlen, die die Gesamtkapazität angeben, etwas kleiner.

              Falsch - kB war _immer_ der Faktor 1000, KB ist traditionell 1024 - da fängts aber auch schon an ;) MB und MB kennt hingegen schon keine Unterscheidung mehr.

              Dadurch, dass man also so aufs Korinthenkacken besteht, schafft man Probleme, wo eigentlich gar keine sind.

              Auf lange sicht, werden dadurch aber Probleme behoben: die Euro-Umstellung haben wir auch überlebt: und mal ehrlich wir haben davon profitiert.

              [*] Wobei ich die cm hier für einen Griff ins Klo halte; fast überall in der Technik wird in Meter oder Millimeter gemessen, Zentimeter sind völlig unüblich.

              Natürlich, cm ist auch keine SI-Basiseinheit oder eine vielfaches einer 3-er-Potenz davon.

              1. Moin!

                Nein, die Diskettenhersteller ;) eine 1.44"-Diskette rechnet "ganz anders" ;) solch eine hat 1,40 MiB (lt. IEC), 1,47 MB (lt. SI), 1,40 MB (lt. Windows bzw. "traditionell") und 1,44 MB (lt. Formfaktor).

                Mag sein, dass deine Speichergrößenangaben stimme, aber diese Diskette hatte garantiert keine 1.44 ZOLL. Sondern 3,5 Zoll.

                Und es wäre auch höchst ungewöhnlich, die Längenangabe 1.44" in irgendeiner Form in eine Speichergröße (z.B. 1,44 MB) umrechnen zu können.

                Eine 3,5"-Festplatte ist übrigens exakt 100 mm breit - das ist ein gutes Stück mehr als 3,5 Zoll, eine 3,5"-Floppy ist etwa 3,54 Zoll breit (90 mm).

                3,5" ist die vereinheitlichte Bauform-Größe. Genau wie 5,25" auch. Disketten der Größe 3.5" erfordern halt nur Laufwerke, die leicht größer sind und deshalb einen entsprechend breiten Einschub erfordern. Und weil Festplatten relativ schnell auch nur noch kleine rotierende Scheiben hatten, hat man sich vermutlich gedacht: Wo im Gehäuse schraubt man die am besten fest? Ah, die Schächte für 3,5"-Diskettenlaufwerke sind ganz prima, machen wir das Gehäuse der Festplatte doch genauso groß. Wobei: So eine Überlegung ist damals nicht neu gewesen, vorher hat man dieselbe Übung für Diskettenlaufwerke und Festplatten mit 5,25" auch schon vollführt. Damals noch mit '5,25"-Einschub volle Bauhöhe' oder 'halbe Bauhöhe' - letzteres ist das, was man heutzutage als "ein Laufwerksplatz" kennt, volle Bauhöhe ist der Platz für zwei Laufwerke.

                - Sven Rautenberg

                1. Mag sein, dass deine Speichergrößenangaben stimme,

                  Ja, die stimmen - grade nochmal geprüft.

                  aber diese Diskette hatte garantiert keine 1.44 ZOLL. Sondern 3,5 Zoll.

                  Klar doch - danke für die Korrektur.

                  Und es wäre auch höchst ungewöhnlich, die Längenangabe 1.44" in irgendeiner Form in eine Speichergröße (z.B. 1,44 MB) umrechnen zu können.

                  Jaja - Ich guck noch mal in die Flasche, wie spät das ist :p

                  3,5" ist die vereinheitlichte Bauform-Größe. Genau wie 5,25" auch. Disketten der Größe 3.5" erfordern halt nur Laufwerke, die leicht größer sind und deshalb einen entsprechend breiten Einschub erfordern. Und weil Festplatten relativ schnell auch nur noch kleine rotierende Scheiben hatten, hat man sich vermutlich gedacht: Wo im Gehäuse schraubt man die am besten fest? Ah, die Schächte für 3,5"-Diskettenlaufwerke sind ganz prima, machen wir das Gehäuse der Festplatte doch genauso groß. Wobei: So eine Überlegung ist damals nicht neu gewesen, vorher hat man dieselbe Übung für Diskettenlaufwerke und Festplatten mit 5,25" auch schon vollführt. Damals noch mit '5,25"-Einschub volle Bauhöhe' oder 'halbe Bauhöhe' - letzteres ist das, was man heutzutage als "ein Laufwerksplatz" kennt, volle Bauhöhe ist der Platz für zwei Laufwerke.

                  Ich hab' nichts anderes behauptet ;)

        2. Re:

          Schlauer Plan ;) bedenke allerdings die MB != MiB-Problematik. Ich kann auf den Sprung nicht sagen, ob PHP korrekt mit der Basis 1.000 (10^3) für die SI-Vorsätze rechnet oder fälschlicherweise mit 1.024 (2^10) rechnet und trotzdem SI-Präfixe verwendet.

          Die Dimension des Bildes hat nichts mit der PHP-internen Speicherzuteilung, wie sie von memory_get_usage() wiedergegeben wird, zu tun. Sie ist zwar abhängig vom Datenvolumen, muss jedoch nicht direkt proportional sein. Daher finde ich den Plan alles andere als „schlau“.

          Gruß aus Berlin!
          eddi

          1. Die Dimension des Bildes hat nichts mit der PHP-internen Speicherzuteilung, wie sie von memory_get_usage() wiedergegeben wird, zu tun. Sie ist zwar abhängig vom Datenvolumen, muss jedoch nicht direkt proportional sein. Daher finde ich den Plan alles andere als „schlau“.

            Natürlich nicht - aber wenn memory_get_usage() - memory_limit kleiner ist als das Bild als Bitmap im Speicher benötigen wird, kann es nicht funktionieren.

            1. Re:

              Die Dimension des Bildes hat nichts mit der PHP-internen Speicherzuteilung, wie sie von memory_get_usage() wiedergegeben wird, zu tun. Sie ist zwar abhängig vom Datenvolumen, muss jedoch nicht direkt proportional sein. Daher finde ich den Plan alles andere als „schlau“.

              Natürlich nicht - aber wenn memory_get_usage() - memory_limit kleiner ist als das Bild als Bitmap im Speicher benötigen wird, kann es nicht funktionieren.

              Mal abgesehen davon, dass ich Deinen Satz nach allen mir erdenklichen Auslegungen, und diese reichen von einer Subtraktion (pseudocode: memory_get_usage() - ini_get('memory_limit');) bis hin zum Nutzen von Parallelabfragen mittels register_tick_function(), immer noch nicht verstehe, ist die Berechnung der Speichergröße zur Basis der Bildabmaße aufgrund der nicht berechenbaren PHP-internen Speicherzuteilung unnötige Arbeit. Wie vorgeschlagen, was Tom auch so macht, wie Vinzenz einwandte, sollte mit memory_get_usage() und einer Pausale die maximalen Dimensionen festgesetzt werden.

              Aber aus der von DiBo33 benannten Quelle wird auch ersichtlich, woran es Deiner Rechnung krankt. GDlib hat die Basis 40Bit.

              Gruß aus Berlin!
              eddi

      2. Re:

        Also muss ich aus den Werten von getimagesize() den Speicherplatz, nach suits Beispiel, berechnen...

        Nein.

        ...und prüfen ob der den Wert von memory_get_usage() nicht überschreitet?

        Nein.

        Bzw. etwas Tolleranz schaffen?

        Ja.

        Wenn ja, wieviel wär angemessen?

        Soviel, wie Dein Script maximal verbraucht.

        Ich würde Dich bitten, zunächst einmal memory_get_usage() auszuprobieren und zu verstehen, was diese Funktion zurückgibt. Setzte diese Funktion an verschiedene Stellen in Dein Script und lasse Dein Script mit ansteigenden Dimensionen von Bildern bis zu der Größe laufen, wo es zu Speicherlimitüberschreitungen kommt. Davon ziehst Du pauschal einfach mal 5% Bildfläche ab und hast Deinen Richtwert, mit dem Du im Script vorab entscheiden kannst, ob das Bild zu groß ist.

        Gruß aus Berlin!
        eddi

        1. Nein.
          Nein.

          Warum nicht? Es schwadet nicht, vorher zu prüfen und ggf. zu sagen "Njet, wird nicht klappen".

      3. Hallo,

        Also muss ich aus den Werten von getimagesize() den Speicherplatz, nach suits Beispiel, berechnen und prüfen ob der den Wert von memory_get_usage() nicht überschreitet? Bzw. etwas Tolleranz schaffen? Wenn ja, wieviel wär angemessen?

        wie ich mal schrieb:

        Für das Bild brauchst Du mindestens:

        Anzahl Pixel ( = Höhe * Breite) * Farbtiefe in Bytes pro Pixel
        und halt eben * einem empirisch zu ermittelnden Overhead, der größer ist als 1.

        Höhe * Breite * Farbtiefe = noch zur Verfügung stehender Speicher
        ist eine sichere Obergrenze. Dann wirst Du die Fehlermeldung mit Sicherheit erhalten.

        Tom schlägt für den Overhead einen Faktor von 1.65 vor.

        Freundliche Grüße

        Vinzenz

        1. Hey Vinzenz!

          und halt eben * einem empirisch zu ermittelnden Overhead, der größer ist als 1.
          Tom schlägt für den Overhead einen Faktor von 1.65 vor.

          Wozu ist der Overhead?

          Tom seine schöne Funktion (leider fehlen ein paar Kommentare, ich versuch sie mal nachzuvollziehen):

            
          // ich denk mal:  
          // $_imageinfo = Array aus getimagesize()  
          // $memleft = ?? mein PHP kennt keine solche Konstante  
          function image_check_memory($_imageinfo, $memleft = MEMORY_LEFT)  ## X, Y, bits, channels  
          {  
              ## fehlende Angaben durch Raten ergänzen  
              if (!isset($_imageinfo['bits'])) $_imageinfo['bits'] = 8;  
              if (!isset($_imageinfo['channels']) and $_imageinfo['bits'] == 24) $_imageinfo['channels'] = 1;  
              if (!isset($_imageinfo['channels'])) $_imageinfo['channels'] = 3;  
              // benötigten Speicherplatz berechnen:  
              // (durch 8 teilen für Bits zu Bytes)  
              // wozu ist +65536 ??  
              // wozu ist der Overhead? Größer 1 ist klar, aber wieso 1.65?  
              // Bildbreite * Bildhöhe * Bits * Farbkanäle / 8Bits + 65536) * Overhead  
              // Ergebniss abrunden  
              $memoryNeeded = round(($_imageinfo[0] * $_imageinfo[1] * $_imageinfo['bits'] * $_imageinfo['channels'] / 8 + 65536) * 1.65);  
              // maximal Speicher der zur Verfügung steht * 1048576  
              // wieso 1048576 ??  
              $memoryLimit = intval(ini_get('memory_limit')) * 1048576;  
              // wenn der von PHP verbrauchte Speicher + berechnetem Speicher + $memleft(??) größer als maximal zur Verfügung stehender Speicher  
              if ((memory_get_usage() + $memoryNeeded) + $memleft > $memoryLimit)  
              {  
                  // ist das schlecht  
                  error_log('..');  
                  return false;  
              }  
              // sonst "sollte" mit dem Bild nix schief gehn ;)  
              return true;  
          }
          

          Kannst du mir die Stellen mit den Fragezeichen erklären?
          Die Funktion sieht super aus, vielleicht sollte mal jemand einen Artikel über das Problem schreiben. (oder gibts schon?)

          Danke und Grüße, Matze

          1. // wieso 1048576 ??

            Weil 1 "MB" bzw. MiB exakt 1048576 Byte entspricht - wenn memory_limit also auf 128M steht, kommt man durch die Multiplikation mit 1048576 auf den richtigen Wert.

            1. Weil 1 "MB" bzw. MiB exakt 1048576 Byte entspricht - wenn memory_limit also auf 128M steht, kommt man durch die Multiplikation mit 1048576 auf den richtigen Wert.

              Ja klar, darauf hätt ich auch kommen können.
              Und wozu noch +65536? Und wie kommt Tom auf den Overhead?

              Grüße, Matze

              1. Hallo,

                Und wozu noch +65536? Und wie kommt Tom auf den Overhead?

                empirisch ermittelt.

                Freundliche Grüße

                Vinzenz

                1. Hallo Ingrid,

                  Und wozu noch +65536? Und wie kommt Tom auf den Overhead?
                  empirisch ermittelt.

                  nimmt man den Hinweis von DiBo dazu, dann kann man stets mit einer Farbtiefe von 40 Bit rechnen (das ist das 5/3-fache von 24 Bit und ergibt somit das 1,6666... fache). Worauf Tom völlig zurecht hinwies: danach benötigt man noch etwas Speicherplatz für die Operationen mit diesem Bild. Du hast sonst ein Bild im Speicher, mit dem Du nichts anfangen kannst :-)

                  Freundliche Grüße

                  Vinzenz

                  1. Super, man muss eure Hinweise nur richtig verknüpfen, dann setzt sich das Puzzle sehr schön zusammen.
                    Und bislang hab ich sogar alles verstanden :)

                    Und jetzt noch der letzte Punkt.
                    Wie kommt Tom auf $memleft = MEMORY_LEFT?
                    Das rechnet er zu dem benötigten Speicher und dem bereits belegten Speicher hinzu.

                    Grüße, Matze

                    1. Hallo,

                      Wie kommt Tom auf $memleft = MEMORY_LEFT?
                      Das rechnet er zu dem benötigten Speicher und dem bereits belegten Speicher hinzu.

                      die Reserve, damit PHP noch was machen kann, wie ich schon erwähnte:

                      "danach benötigt man noch etwas Speicherplatz für die Operationen mit
                           diesem Bild. Du hast sonst ein Bild im Speicher, mit dem Du nichts
                           anfangen kannst :-)"

                      Freundliche Grüße

                      Vinzenz

                      1. die Reserve, damit PHP noch was machen kann, wie ich schon erwähnte:

                        Wie jetzt? Ich dachte, dafür wären die 65536?
                        Zumal Tom $memleft eine Konstante übergibt und ich nicht weiß wie die Funktion aufgerufen wird, verwirrt mich dass hier:

                          
                        function image_check_memory($_imageinfo, $memleft = MEMORY_LEFT)  
                        {  
                            /* .. */  
                            if ((memory_get_usage() + $memoryNeeded) + $memleft > $memoryLimit)  
                            /* .. */
                        

                        Was kommt also in $memleft?

                        Matze

                        1. Hallo,

                          die Reserve, damit PHP noch was machen kann, wie ich schon erwähnte:

                          Wie jetzt? Ich dachte, dafür wären die 65536?

                          durch die Addition kommt Tom mit seiner empirischen Vorgehensweise dichter an die von DiBo angegebenen 5/3 heran :-)

                          Zumal Tom $memleft eine Konstante übergibt und ich nicht weiß wie die Funktion aufgerufen wird, verwirrt mich dass hier:
                          [code lang=php]
                          function image_check_memory($_imageinfo, $memleft = MEMORY_LEFT)
                          Was kommt also in $memleft?

                          Tom schreibt doch selbst:

                          <zitat>
                              Die Konstante MEMORY_LEFT sollte nicht unter 100000 liegen. Sie
                              kennzeichnet den Speicher, der noch für weitere Operationen übrig
                              bleiben muss.
                          </zitat>

                          Freundliche Grüße

                          Vinzenz

                          1. <zitat>
                                Die Konstante MEMORY_LEFT sollte nicht unter 100000 liegen. Sie
                                kennzeichnet den Speicher, der noch für weitere Operationen übrig
                                bleiben muss.
                            </zitat>

                            Oh. Ja, mein Hirn funktioniert auch nicht anders als das von Kelly Bundy.
                            Wenn was neues rein kommt, fliegt was anderes raus.
                            Tom hätte den Hinweis mal unter die Funktion schreiben sollen ;D

                            Aber wieso eine Konstante? Wäre ein default von 100k nicht sinnvoller?

                            Grüße, Matze

                            1. Hello,

                              Aber wieso eine Konstante? Wäre ein default von 100k nicht sinnvoller?

                              Klar, man könnte Funktionen auch mit 255 Argumenten ausstatten, von denen 253 als Default voreingetellt sind. Dumm nur, wenn man dann an ungünsiger Stelle einen dieser Defaults wieder ändern muss...

                              Das ist dann wieder ein Argument für OOP in PHP. Denn dann müsste man wirklich nur den Setter für diese eine Änderung aufrufen vorher.

                              Nur, dass dann die 100.000 Byte, die für die meisten Fehler- und Ausgabefunktionen in Scripten ausreichen, eventuell durch den OOP-Oberhead frü das Objekt verballert hat *höhöhö*

                              Ich habe bei der Funktion ausdrücklich erwähnt, dass sie keinesfalls perfekt ist, also eher aus dem Bauch raus entstanden ist. Der Kopf hat nur manchmal ungläubig geschüttelt dabei, dass sowas aus dem Bauch raus überhaupt funktionieren kann. Aber im Rückblick ist es doch wieder alles logisch ;-)

                              Übrigens habe ich in zwei kleineren Bildbearbeitungsprojekten eine solche Funktion eingestzt und die Kunden haben seitdem nie wieder Ärger mit dem Memory-Limit gemeldet. Es scheint also gut so zu sein.

                              Liebe Grüße aus dem schönen Oberharz

                              Tom vom Berg

                              --
                               ☻_
                              /▌
                              / \ Nur selber lernen macht schlau
                              http://bergpost.annerschbarrich.de
                              1. Klar, man könnte Funktionen auch mit 255 Argumenten ausstatten, von denen 253 als Default voreingetellt sind. Dumm nur, wenn man dann an ungünsiger Stelle einen dieser Defaults wieder ändern muss...

                                Das ist auf jeden Fall ein Argument bei komplexeren Funktionen.
                                In deinem Fall besitzt die Funktion aber nur 2 Parameter.
                                Da _könnte_ man den zweiten auch vorbelegen.
                                Die Konstante hat mich halt nur verwirrt.
                                Natürlich weil ich den Text über der Funktion nur unaufmerksam überflogen habe.

                                Ich habe bei der Funktion ausdrücklich erwähnt, dass sie keinesfalls perfekt ist, also eher aus dem Bauch raus entstanden ist. Der Kopf hat nur manchmal ungläubig geschüttelt dabei, dass sowas aus dem Bauch raus überhaupt funktionieren kann. Aber im Rückblick ist es doch wieder alles logisch ;-)

                                Sie scheint aber sehr gut zu funktionieren, deshalb könnte man ihr den Status "perfekt" meinetwegen auch gern verabreichen ;)

                                Übrigens habe ich in zwei kleineren Bildbearbeitungsprojekten eine solche Funktion eingestzt und die Kunden haben seitdem nie wieder Ärger mit dem Memory-Limit gemeldet. Es scheint also gut so zu sein.

                                Ich hab sie mal in meinen Ordner mit nützlichen Codeschnipseln abgelegt. Ich brauch sie sicher noch mehr als 1 mal.

                                Grüße, Matze

                2. Und wozu noch +65536? Und wie kommt Tom auf den Overhead?
                  empirisch ermittelt.

                  Ok, aber aus welchen Werten?
                  Ich mein, die Zahl ist ja nicht grad irgend was "glattes" wie vllt. 65.000 oder 66.000.
                  Wieso ausgerechnet 65536? Oder wieso 536, oder wieso 36... :)

                  Bitte um Stopfung meiner Wissenslücke.

                  Matze

                  1. Hallo,

                    Und wozu noch +65536? Und wie kommt Tom auf den Overhead?
                    empirisch ermittelt.
                    Ok, aber aus welchen Werten?

                    vielleicht auch nur geschätzt, willkürlich angenommen.

                    Ich mein, die Zahl ist ja nicht grad irgend was "glattes"

                    Oh doch! Das ist genau 2^16, also 0x10000 oder 64k. ;-)

                    Ciao,
                     Martin

                    --
                    Gott hilft niemandem, er erfreut sich nur an unseren Leiden.
                      (Ashura)
                    1. Hey Martin!

                      Ich mein, die Zahl ist ja nicht grad irgend was "glattes"
                      Oh doch! Das ist genau 2^16, also 0x10000 oder 64k. ;-)

                      Doktor Kawashima lässt grüßen.
                      Kann man sowas nicht als Kommentar in die Funktion schreiben? ;D
                      Danke für die Erleuchtung!

                      Matze

                      1. Hello,

                        Kann man sowas nicht als Kommentar in die Funktion schreiben? ;D

                        Dazu müsste man die ganze Thread-Kette zurückverfolgen.
                        Da sich außer Engin und mir sich damals keiner mehr aktiv beteiligt hat, haben wir die Doku nicht noch mal vorgetragen...

                        Man könnte das aber nun mal mnachholen :-))

                        Liebe Grüße aus dem schönen Oberharz

                        Tom vom Berg

                        --
                         ☻_
                        /▌
                        / \ Nur selber lernen macht schlau
                        http://bergpost.annerschbarrich.de
                        1. Hey Tom!

                          Man könnte das aber nun mal mnachholen :-))

                          Wurde ja nun in diesem Thread nachgeholt :)
                          Zum einen durch Vinzenz ausführliche Erklärungen,
                          zum anderen durch meine paar hinzugefügten Kommentarzeilen.

                          Aber insgesamt ist deine Funktion halt genau das, was ich gesucht habe.
                          Danke dafür!

                          Und das Thema mal in einem Artikel anzureissen kann sicher auch nicht schaden :)

                          Grüße, Matze

        2. Hello,

          Tom schlägt für den Overhead einen Faktor von 1.65 vor.

          ... den ich auch aufgrund erheblicher Recherche aus Threads von Verwendern der Image-Funktionen ermittelt habe und mir nicht selbst aus den Fingern gesagt habe. Er hat sich scheinbar bewährt bisher. Ich habe damit damals noch ein wenig herumexperimentiert, konnte ihn aber nicht wirklich ernsthaft anzweifeln, weder nach unten, noch nach oben.

          Das hängt wohl mit der etwas komplexeren Speicherverwaltung der Funktionen, von PHP und dem jeweils verwendeten Basis-System zusammen. Auf Linux-Systemen (32 Bit) konnte man ihn etwas reduzieren, ohne Fehlermeldungen zu kassieren.

          Wesentlich ist die vorherige Nutzung von

          $_dummy = getimagesize($filename, $_imageinfo);

          http://de2.php.net/manual/de/function.getimagesize.php

          Das $_imageinfo wid dann, wenn $_dummy !== false ist, wieder in die Funktion

          $ok = image_check_memory($_imageinfo, $memleft = MEMORY_LEFT, $logpath)

          eingesetzt. $logpath fehler hier noch. Den sollte man angeben können. In der dargestellten Funktion war er fälschlicherweise noch auf Engins /var/log/web04/php_error_log fest verdrahtet.

          Liebe Grüße aus dem schönen Oberharz

          Tom vom Berg

          --
           ☻_
          /▌
          / \ Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
    3. Hey eddi!

      Wenn ich es jetzt richtig verstanden habe, gibt mir memory_get_usage() aber den "verbrauchten" Speicher an, nicht den, den der noch "frei" ist!?

      <?php  
      // This is only an example, the numbers below will  
      // differ depending on your system  
      echo memory_get_usage() . "\n"; // 36640  
      $a = str_repeat("Hello", 4242);  
      echo memory_get_usage() . "\n"; // 57960  
      unset($a);  
      echo memory_get_usage() . "\n"; // 36744  
      ?>
      

      Allerdings dürfte der letzte Kommentar, die Frage nach der Umrechnung beantworten.

      Grüße, Matze

      1. Hallo,

        Wenn ich es jetzt richtig verstanden habe, gibt mir memory_get_usage() aber den "verbrauchten" Speicher an, nicht den, den der noch "frei" ist!?

        den musst Du vom Memorylimit abziehen, um zu ermitteln, was noch übrig ist, siehe z.B. Toms Vorschlag.

        Freundliche Grüße

        Vinzenz