Baba: Ständige Abstürze in Firefox bei eigener Webanwendung

Hallo,

ich habe mir eine Anwendung gebaut, um Informationen aus Fotos zu digitalisieren (Positionen von Sedimentpartikeln). Ich habe es als Website gebaut und es läuft auf localhost. Im Wesentlichen habe ich einen Bildbereich, wobei bei Mousewhell scroll die Bilder ausgetauscht werden (die Bilder sind absolut-positioniert). Per Ajax wird jeweils das fünfte Bild im Voraus geladen und ältere als 5 werden rausgeschmissen, sodass zu einem Zeitpunkt immer nur 10 Bilder im DOM eingetragen sind. Mouseclicks werden abgefragt und in einer DB gespeichert und mittels einer flot.js Grafik auch gleich angezeigt. Das funktioniert auch alles ganz gut. Nur: nach ca 200 Klicks stürzt regelmäßig der Browser ab. Und ich weiß nicht genau wieso. Die img-Elemente werden wirklich wieder per js aus dem DOM geschmissen. Und die flot-Graphik zeigt immer nur die Klicks in einem Bild an (wenige Datenpunkte).

Im Absturzbericht finde ich dann immer sowas wie SystemMemoryUsePercentage: 80. Was mir sehr hoch vorkommt.

a) wie finde ich raus, was dafür verantwortlich ist?
b) wie kann ich bei Debuggen vorgehen?

Vielen Dank für alle Hilfsansätze.

Cheers,
Baba

--
Baba kommt von Basketball
  1. Ja, warum den ditte? Habe einfch mal den Task-Manager beobachtet und sehe die Arbeitsspeicherverbrauch geht hoch auf 2.8GB bevor er abstürzt. Das MUSS dann an den Bildern liegen. Witzigerweise ist es aber so, wenn ich bei 1.2GB liege und warte, geht der Arbeitsspeicherverbrauch langsam runter! Gibt es einen Weg zu verhindern, dass die Bilder im RAM bleiben? Wie gesagt, im DOM sind sie nicht mehr.

    Cheers,
    Baba

    --
    Baba kommt von Basketball
    1. Hallo Baba,

      wie entfernst du denn die Bilder aus dem DOM? Und, wie kommen sie rein?

      Gruß, Jürgen

      1. Hallo,

        so kommen sie rein

        $.ajax({  
            url: loadurl+"&imgnr="+imgnr  
          }).done(function(result) {  
            if(!$("img#img-"+imgnr).length){  
              if(delta < 0 ) $("#image").prepend(result);  
              else $("#image").append(result);  
              if(imgnr == CurrentImgNr) ShowImg(imgnr);  
            }  
          });
        

        delta ist der Rückgabewert vom Scroll (hoch- oder runterscrollen). result ist image-Element:
        <img alt="loading..." data-desc="" data-ts="1405189216" title="2014-07-12_20-20-16.jpg" class="preloading" id="img-7" src="/2014-07-12_20-20-16.jpg" />

        Ich baue das serverseitig zusammen weil ich Informationen über das Bild generieren muss.

        So gehen sie raus:

        $("img#img-"+imgnr).remove();  
        
        

        Cheers,
        Baba

        --
        Baba kommt von Basketball
        1. Hallo Baba,

          so kommen sie rein

          $.ajax({

          url: loadurl+"&imgnr="+imgnr
            }).done(function(result) {
              if(!$("img#img-"+imgnr).length){
                if(delta < 0 ) $("#image").prepend(result);
                else $("#image").append(result);
                if(imgnr == CurrentImgNr) ShowImg(imgnr);
              }
            });

          
          >   
          > delta ist der Rückgabewert vom Scroll (hoch- oder runterscrollen). result ist image-Element:  
          > `<img alt="loading..." data-desc="" data-ts="1405189216" title="2014-07-12_20-20-16.jpg" class="preloading" id="img-7" src="/2014-07-12_20-20-16.jpg" />`{:.language-html}  
          >   
          > Ich baue das serverseitig zusammen weil ich Informationen über das Bild generieren muss.  
          >   
          > So gehen sie raus:  
          > ~~~javascript
          
          $("img#img-"+imgnr).remove();  
          
          > 
          
          

          ich habe keine Ahnung, wie jquerry mit den Daten umgeht. Meine Vermutung: beim Überschreiben eines Objekts bleiben Reste im Speicher, evtl. das Objekt von Hand löschen (= null).

          Gruß, Jürgen

          1. ich habe keine Ahnung, wie jquerry mit den Daten umgeht. Meine Vermutung: beim Überschreiben eines Objekts bleiben Reste im Speicher, evtl. das Objekt von Hand löschen (= null).

            Hm, ich denke remove() sollte ziemlich gründlich sein. Aber, um sicherzugehen, wie sollte ich das DOM-Elemente d.M.n löschen, wenn ich kein Objekt davon erzeuge?

            Vielen Dank,
            Baba

            --
            Baba kommt von Basketball
            1. Hallo Baba,

              Hm, ich denke remove() sollte ziemlich gründlich sein. Aber, um sicherzugehen, wie sollte ich das DOM-Elemente d.M.n löschen, wenn ich kein Objekt davon erzeuge?

              DOM Elemente kannst du mit removeChild entfernen, und vergiss nicht, auch eventuell vorhandene Objekte oder Arrays zu löschen (= null).

              Gruß, Jürgen

              1. Leider kein Erfolg. Hier wird sogar gesagt, es gibt gar keine Lösung. Was sehr schade ist, weil ich ein gutes Tool entwickelt habe, was mir bei der Arbeit sehr hilft. Ich hatte vorher mit versucht mit imageJ zu arbeiten, was (als Desktopversion) ebenfalls Probleme mit dem Speicher hatte...

                und vergiss nicht, auch eventuell vorhandene Objekte oder Arrays zu löschen (= null).

                Ich hatte nie Referenzen auf das DOM element. Oder ich verstehe Dich hier immer noch nicht...

                Vielen Dank.
                Baba

                --
                Baba kommt von Basketball
                1. Hallo Baba,

                  wie ich schon schrieb, ich kenne mich mit jquerry nicht aus. Aber dein Code sieht so aus, als würden die Bilder per http-Request (ajax) nachgeladen und dann ins DOM eingebunden. Dazu müssen die Bilddaten ja "irgendwo" zwischengespeichert werden. Beim löschen müssen dann sowohl das "irgendwo" als auch das img-Element gelöscht werden.

                  Hast du schon mal versucht, das nachladen der Bilder "zu Fuß" zu erledigen? Also

                  im = document.createElement("img");  
                  im.onload = function() { ... };  
                  im.onerror = function() { ... };  
                  im.src = "dasNächsteBitte.jpg";  
                  wosHinSoll.apendChild(im);
                  

                  und Löschen dann mit

                  im.parentNode.removeChild(im);  
                  im = null;
                  

                  (ungetestet)

                  Gruß, Jürgen

                  1. Hallo JürgenB,

                    vielen Dank für Deine Antwort.

                    dein Code sieht so aus, als würden die Bilder per http-Request (ajax) nachgeladen und dann ins DOM eingebunden.

                    Nunja. Eigentlich wird nur ein Tag abgeholt, e.g. "<img id='img-122' src='/pic/17_19_01.jpg' data-ts='1451235425'>. Der könnte eigentlich auch im JS generiert werden, wenn ich die Dateinamen kennen würde (faktisch sende ich aber nur die Nr. im Ajax-Request und ein Controller sucht dann das passende Bild mit Dateinamen und TS).

                    Dazu müssen die Bilddaten ja "irgendwo" zwischengespeichert werden. Beim löschen müssen dann sowohl das "irgendwo" als auch das img-Element gelöscht werden.

                    Bilddaten werden also nicht per AJAX-Request geholt.

                    Hast du schon mal versucht, das nachladen der Bilder "zu Fuß" zu erledigen?

                    So müsste ich für jedes Bild ein Objekt erzeugen, was ich sonst nicht machen muss...

                    Cheers,
                    Baba

                    --
                    Baba kommt von Basketball
    2. Wie gesagt, im DOM sind sie nicht mehr.

      Sind sie vielleicht noch im Script?

      1. Wie gesagt, im DOM sind sie nicht mehr.
        Sind sie vielleicht noch im Script?

        Was bedeutet das?

        Cheers,
        Baba

        --
        Baba kommt von Basketball
        1. Was bedeutet das?

          Wenn du ein Bild per JS lädst und dort eine Variable mit dem Bild hältst, dann ist das Bild solange im Speicher, solange es diese Variable gibt.

          1. Wenn du ein Bild per JS lädst und dort eine Variable mit dem Bild hältst, dann ist das Bild solange im Speicher, solange es diese Variable gibt.

            Ich verstehe immer noch nicht genau was Du meinst mit "eine Variable mit dem Bild halten". So was wie

              
            imgvar = $("#img-214");  
              
            
            

            Ich sowas in der Art an keiner Stelle. Immer wenn ich das Bild anspreche verwende ich den jquery Selektor neu.

            Cheers,
            Baba

            --
            Baba kommt von Basketball
    3. Aloha ;)

      Ja, warum den ditte? Habe einfch mal den Task-Manager beobachtet und sehe die Arbeitsspeicherverbrauch geht hoch auf 2.8GB bevor er abstürzt. Das MUSS dann an den Bildern liegen. Witzigerweise ist es aber so, wenn ich bei 1.2GB liege und warte, geht der Arbeitsspeicherverbrauch langsam runter! Gibt es einen Weg zu verhindern, dass die Bilder im RAM bleiben? Wie gesagt, im DOM sind sie nicht mehr.

      Das hört sich für mich stark danach an, dass dein Browser *seinen* RAM-Speicher nicht schnell genug leert. AFAIK sind das aber Browser-Interna, die du als Seitenentwickler nicht steuern kannst. Anderes wäre mir neu.

      Schon mal einen anderen Browser probiert?

      Möglich, dass das auch dem geschuldet ist, dass die Seite nicht neu geladen wird. Es kann gut sein, dass der Browser die alten Daten im RAM dann eher verschrottet, wenn er eine "neue" Seite lädt. Wäre auch mal einen Test wert... Du könntest die Seite z.B. nach 10 Bildern mit geeigneten Parametern (damit du da weitermachen kannst wo du warst) neu laden lassen, um ein "Neuladen" (auf den fast selben Content) zu erzwingen...

      Oder noch eine Idee (für die ich jetzt eventuell gesteinigt werde, aber vielleicht ists in diesem Fall ja angebracht): Was ist, wenn die Bilder eben NICHT auf der aktuellen Seite liegen, sondern z.B. per iframe eingebunden werden? (Natürlich eingebunden in ein HTML-Dokument, z.B. indem dein Server generisch ein HTML-Dokument zusammenstellt, in dem das fragwürdige Bild komplett abgebildet ist und sonst nix / wahlweise auch per GET-Parameter-Sniffing und JavaScript...) Das müsste (imho) sicherstellen, dass nach Entfernen des iframe die im iframe benötigten Ressourcen direkt verworfen werden... Imho stellt der Inhalt in einem iframe für die meisten Browser eine extra Seite dar, die auch über eigene Ressourcen verfügt - die bei Schließen verworfen werden müssten... Das Abfangen der Klicks kann entweder über den iframe erfolgen, oder - was ich für eine ebenso praktikable Idee halte - über ein über den iframe gelegtes, transparentes DIV geschehen...

      Interessante Sache - meld dich wenn du eine Lösung hast, würde mich auch interessieren...

      Grüße,

      RIDER

      --
      Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
      ch:? rl:| br:> n4:? ie:% mo:| va:) js:) de:> zu:) fl:( ss:| ls:[
      1. Das hört sich für mich stark danach an, dass dein Browser *seinen* RAM-Speicher nicht schnell genug leert. AFAIK sind das aber Browser-Interna, die du als Seitenentwickler nicht steuern kannst. Anderes wäre mir neu.

        Das hört sich für mich auch so an. Test: Wenn ich 15 Bilder lade ist er bei ungefähr 1 gb Ram. Wobei ein Bild nur 2MB hat?!? Wenn ich den Tab dann schließe sind gleich mal 200MB frei, der Rest geht aber langsam (ca. 30Sek) runter.

        Schon mal einen anderen Browser probiert?

        Gute Idee, hätte ich auch schonmal drauf kommen können :)
        Chrome, bspw. löscht überhaupt nichts. Insgesamt geht alles ein bisschen fixer, er kommt auch auf seine 2GB benötigt dafür aber 300 Bilder+. Bleibt man stehen, bleibt die Arbeitsspeicheranzeige auch stehen und geht gar nicht runter. Abgestürzt ist er dann bei 500 Bildern, bei 2.2gb.

        Möglich, dass das auch dem geschuldet ist, dass die Seite nicht neu geladen wird. Es kann gut sein, dass der Browser die alten Daten im RAM dann eher verschrottet, wenn er eine "neue" Seite lädt. Wäre auch mal einen Test wert...

        Firefox macht bei Neuladen nichts anders, als bei Warten oder sogar Tab schliessen. Bzws, macht erst einen 200mb Sprung und geht dann gemütlich langsam runter.

        Oder noch eine Idee (für die ich jetzt eventuell gesteinigt werde, aber vielleicht ists in diesem Fall ja angebracht): Was ist, wenn die Bilder eben NICHT auf der aktuellen Seite liegen, sondern z.B. per iframe eingebunden werden?

        Das dürfte dann ja auch keinen Unterschied machen, im FF.

        Interessante Sache - meld dich wenn du eine Lösung hast, würde mich auch interessieren...

        Ich berichte auf jeden Fall.

        Cheers,
        Baba

        --
        Baba kommt von Basketball
  2. Hallo,

    Vielen Dank für alle Hilfsansätze.

    Ich hatte das Problem auch bei einer Webanwendung, nach einiger Zeit hatte ich >80% CPU-Auslastung.
    Deaktivieren des Firebugs hatte zur Folge, das alles bei <10% lief.

    vg ichbinich

    --
    Kleiner Tipp:
    Tofu schmeckt am besten, wenn man es kurz vor dem Servieren durch ein saftiges Steak ersetzt...
    1. Ich hatte das Problem auch bei einer Webanwendung, nach einiger Zeit hatte ich >80% CPU-Auslastung.
      Deaktivieren des Firebugs hatte zur Folge, das alles bei <10% lief.

      Guter Punkt. Hatte ich auch schonmal. Daher habe ich es auch ohne Firebug getestet. Ohne Erfolg.

      Cheers,
      Baba

      --
      Baba kommt von Basketball
  3. Das Problem, Bilder effektiv aus dem Speicher zu werfen, scheint bekannt zu sein.

    Ich hatte jetzt einen guten Fortschritt mit der Entfernung des Source Attributes:

    $("img#img-"+imgnr).removeAttr('src');  
    $("img#img-"+imgnr).remove();
    

    Der Firefox bleibt deutlich unter den zuvor erreichten Werten (RAM) und ist heute noch nicht einmal abgestürzt. Falls das nicht ausreicht, wäre auch noch daran zu denken, die <img> Elemente zu recyclen. Da ich immer neun vorhalte (um Preloading zu betreiben) wird das allerdings etwas hakelig.

    Wenig Erfolg hatte ich damit, die Quelle zu überschreiben:
    //$("img#img-"+imgnr).attr('src','data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAA‌​LAAAAAABAAEAAAICRAEAOw%3D%3D');

    Cheers,
    Baba

    --
    Baba kommt von Basketball