Anzeige:
Ergebnis 1 bis 8 von 8

Thema: Memory leak in repaint

  1. #1
    Registrierter Benutzer Avatar von BlueJay
    Registriert seit
    27.08.2004
    Beiträge
    825

    Memory leak in repaint

    Hallo Leute,

    Da läuft eine Anwendung, die verschiedene Screens zeigt, einer davon eine Animation, die im 50ms-Takt neue Daten liefert.

    Der Task-Manager zeigte, wie sich Sekunde um Sekunde in 4-Byte-Häppchen der Java-Userspace vergrößerte.

    Schuld daran war repaint(), was, in graphics rekursiv aufgerufen wurde, für eine flickerfreie Animation sorgen sollte.
    Code:
      public void paintComponent(Graphics g)
      {
        g.setFont(font);
        switch (aktscreen)
        { case 0: if (levelshown!=p_akt.level) prepare_levelima();
                     mach_feld(g);
                     repaint();
                     break;
          case 1: zeige_stats(g); break;
          case 2: zeige_hilfe(g); break;
          default: zeige_titel(g);
        }
    //    time2=System.currentTimeMillis(); System.out.println((time2-time1)+"ms"); time1=time2;
      }
    (repaint kommt in der obigen Form mit 25-30ms hin, die Koordinaten werden im 50ms-Takt upgedatet.)

    Ich habe das repaint() dann aus paintComponent rausgenommen = Leck war weg, aber keine Animation mehr
    und in den Berechnungsloop reingenomen = Leck war wieder da.

    Second vers., same as the first! Nur, dass die Sch***Ani stockender lief.

    Wie kann ich das leck stopfen und die Animation und deren performance behalten?

    so long,
    BlueJay
    Eigentlich ganz einfach, wenn man's weiss!

  2. #2
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Vielleicht kommt es zu einer Rekursion?

    D.h. repaint() hätte ein paintComponent() zufolge, usw.

    Allerdings müsste dann eigentlich schon ein Stackoverflow passieren.

    Kannst du statt repaint() mal probieren, die paintComponent() der Basisklasse aufzurufen?

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  3. #3
    Registrierter Benutzer Avatar von BlueJay
    Registriert seit
    27.08.2004
    Beiträge
    825
    Es kommt zu einer Rekursion:
    repaint schubst paint oder update an und verkrümelt sich dann wieder. So alle Sekunde dümpelt ein unbedienter Aufruf durchs RAM.
    Angeblich soll repaint dafür sorgen, dass da nur das letzte Update ausgeführt wird.
    http://java.sun.com/products/jfc/tsc...ing/index.html
    Trotzdem vermehrt sich da was unkontrolliert in Pointergröße.

    Die Rekursion als Bestandteil eine Animation ist ja gewollt: nach einem repaint meldete ich das nächste an (vorliegener Text). Anstieg: 4 bytes pro Sekunde, Performance passabel bis gut. (30-60 Frames/Sekunde)

    Dann packte ich das repaint in die Berechnungsroutine, die nur alle 50ms angestoßen wurde. Anstieg: 12 bytes pro Sekunde, Performance am Rand des Erträglichen. (15-20 Frames/Sekunde)

    Berechnungsloop:
    Code:
      public void run()
      { 
        while (Thread.currentThread() == thread1)
        { if (!pausiert) if (!gover)
          { moveit(); // updatet gover und level_fertig
            // mama.drawpanel.repaint();
            if (gover) mama.eintrag(status);
            else if (level_fertig) neu(level+1,status);
          }
          try { Thread.sleep(timetic); }
          catch (InterruptedException e) { break; }
        }
      }
      public void stop()    { thread1=null; }
    Dann habe ich versucht, mit dem Repaint Manager zu arbeiten, wie es der Bugreport für repaint beschrieb. Der Speicherhunger wurde gigantisch, die Performance war im A. (<1Frame/Sekunde), und innerhalb 2 Minuten war das Programm abgestürzt.

    Zu deinem Vorschlag:
    ich komme von aussen nicht an den Graphics-Handler ran, getGraphics auf das JPanel-Derivat returnt mir null, sogar, wenn ich ihn in der JPanelDerivat-Klasse selbst bestimmen lasse. Es gelingt mir nur, den Graphics-Handler auf Images zu bekommen.

    Arbeiten mit update() fällt flach, da ich mit einem JPanel werkele:
    update() is never invoked on Swing components.
    (aus obigem Artikel)
    Eigene Versuche zeigten, dass update komplett ignoriert wird, auch vom JPanel-Derivat selbst.

    Was sol ich machen?
    Nach 100000 Sekunden ein Popup erscheinen lassen:" Bitte beenden Sie das Programm samt Java-Engine, solange Ihr Task-Manager noch aufrufbar ist"?

    so long,
    BlueJay
    Geändert von BlueJay (10-11-2007 um 17:35 Uhr)
    Eigentlich ganz einfach, wenn man's weiss!

  4. #4
    Registrierter Benutzer Avatar von bischi
    Registriert seit
    10.04.2003
    Beiträge
    4.828
    Trotzdem vermehrt sich da was unkontrolliert in Pointergröße.
    Hältst du unbewusst noch irgenwelche Verweise fest? Also irgendwelche Tracker, Variablen,... welche nicht gelöste Abhängigkeiten enthalten? Legst du unbewusst irgenwelche neuen Objekte an? Kopierst du unbewusst irgenwelche Objekte?

    Bspw (nachher zwei Strings!!!):
    String ABC = "AB";
    ABC=ABC+"C";

    MfG Bischi

    "There is an art, it says, or rather, a knack to flying. The knack lies in learning how to throw yourself at the ground and miss it" The hitchhiker's guide to the galaxy by Douglas Adams

    --> l2picfaq.pdf <-- www.n.ethz.ch/~dominikb/index.html LaTeX-Tutorial, LaTeX-Links, Java-Links,...

  5. #5
    Registrierter Benutzer Avatar von BlueJay
    Registriert seit
    27.08.2004
    Beiträge
    825
    Mache ich dauernd

    Dafür schubse ich ja zu Beginn jedes geladenen Musters die GC an. Diese befreit mich aber nicht von dem Schrott.

    Es ist einzig und allein das "selbst angestoßene" repaint. Lässt man das weg, bleibt (bei voller Berechnung und anderer Last) die Vermehrung aus, die Ani leider auch.

    Da ist noch ein BufferedImage (bima), auf das ich zu Beginn male, es dann "nach vorne" bringe. Aber dieses wird nur 1x pro Level erzeugt.
    Zuerst hatte ich die Stadien der Kugeln auf diesem bima erzeugt, aber die Performance ist in dieser Version besser.

    Na, packenmer das hier auch noch rein:
    Code:
      void mach_feld(Graphics g)
      { int i;
        String out;
        g.drawImage(bima,0,0,null);
    //     g.setColor(Color.black); g.fillRect(0,0,sxmax,symax);
        // Feld:
        for (i=0; i<p_akt.maxsprites; i++) if (p_akt.kugel[i].typ>0)
         g.drawImage(ima[p_akt.kugel[i].typ-1],p_akt.kugel[i].x,p_akt.kugel[i].y,null);
        out="Level:"+p_akt.level+"  Status: "+p_akt.status+"   Nachricht: "+p_akt.messi;
        g.setColor(Color.black);
        g.fillRect(32,symax-80,sxmax-64,24);
        g.setFont(font);
        g.setColor(Color.yellow);
        g.drawString(out,64,symax-64);
    
      }
    so long,
    Bluejay
    Eigentlich ganz einfach, wenn man's weiss!

  6. #6
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Zitat Zitat von BlueJay Beitrag anzeigen
    Zu deinem Vorschlag:
    ich komme von aussen nicht an den Graphics-Handler ran, getGraphics auf das JPanel-Derivat returnt mir null, sogar, wenn ich ihn in der JPanelDerivat-Klasse selbst bestimmen lasse. Es gelingt mir nur, den Graphics-Handler auf Images zu bekommen.
    Nein, ich meinte in deiner Implementation von void paintComponent() die Implementierung der Basisklasse aufrufen, d.h. in etwa so

    Code:
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
    
        // dein code
    }
    (Wenn ich das jetzt für Java so richtig im Kopf habe )

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  7. #7
    Registrierter Benutzer Avatar von BlueJay
    Registriert seit
    27.08.2004
    Beiträge
    825
    ... ergibt ein wunderschön gleichmäßiges hellgraues Panel, also noch weniger als ein einfaches paintComponent.

    repaint ist für JPanel schon so gedacht, dass es einen Request zum Neuzeichnen an den GUI-Manager abschickt, der asynchron abgearbeitet wird. Der GUI-Manager. soll angeblich von alleine merken, welcher Request der aktuellste ist und den Rest verwerfen.
    Ich frage mich langsam: Tut es das wirklich? Oder lässt er dem GC*, der wohl noch fauler ist, die ganze Arbeit? Dann wäre das nämlich die wundersame Vermehrung der Pointer.

    Dabei fiel mir auch auf, dass die wundersame Vermehrung sich beschleunigen ließ, wenn man über der Menuleiste hoverte.
    (Die Tooltips hatte ich vorher wieder rausgeschmissen, weil sie die Optik störten).
    Eigentlich ganz einfach, wenn man's weiss!

  8. #8
    Registrierter Benutzer Avatar von BlueJay
    Registriert seit
    27.08.2004
    Beiträge
    825
    Fazit, nachdem das Programm in ein Jar gepackt und einpaar Tage lang mit Unterbrechungen beobachtet wurde:

    Die Speicherfresserei war nach 13-20 Animationsdurchgängen beendet.
    Der Java-Userspace war auf das 2.5fache angewachsen, der Java-Systemspeicher auf das Anderthalbfache (bezogen auf den Zeitpunkt, an dem die Animation gestartet wurde).

    Mal eine ganz dumme Frage: Ist das der Hotspot-Compiler? Mittlerweile gehen die Sprites nämlich ab wie unter C++.

    so long,
    Bluejay
    Geändert von BlueJay (16-11-2007 um 04:48 Uhr)
    Eigentlich ganz einfach, wenn man's weiss!

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •