PDF Report mit Tomcat Heap Space Problem

Status
Nicht offen für weitere Antworten.

y0dA

Top Contributor
Hi!
Vorweg eine kleine Beschreibung was in diesem Zusammenhang in der Web-Applikation passiert:
1. Benutzer loggt sich ein, 2. Wählt eine Selektion aus (welche Länderdaten und hierzu spezifische Werte für Umweltzeug beinhaltet). 3. Schränkt bspw. auf ein Land (Österreich) ein und 4. Läßt sich dann ein Ergebnis anzeigen (JSP). Danach hat der Benutzer dann die Möglichkeit sich dieses Ergebnis inkl einer Karte "auszudrucken", hierzu gibt es einen Button. Das Drucken selbst sieht dann so aus dass ein PDF Dokument im selben Browser Fenster angezeigt wird (mehrere Seiten) und man dann eben das Teil drucken kann.

Und wenn man das nun mit mehreren Benutzern macht, sowie per JMeter mehrmals durchührt, kommt irgendwann ein OutOfMemory von Tomcat. Nun habe ich die Vermutung dass dieser PDF Report einfach nie freigegeben wird und im Tomcat Speicher rumliegt.

Hier der Code:


1.
Code:
/**
     * Ein Export mit der angegebnen Logik wird durchgefuehrt.
     *
     * @param exportLogik Logik die für den Export verwendet werden soll.
     * @param exportIn Daten, die exportiert werden.
     * @param title name of the selection
     * @param layers relative paths to stored gif images, can be null
     */
    public synchronized void process(final String exportLogik,
            final DataTable exportIn, final String title, final List<String> layers) {
        this.exportOut.reset();
        ConfigExportItem config = ConfigExportLocator.getInstance().getConfigItem(exportLogik);
        ExportLogik logik = (ExportLogik) this.findObjectForGivenClass(config.getExportKlasse());
        
        Calendar c = Calendar.getInstance();
        String fileNameDate = c.get(Calendar.YEAR) + "_"
                           + (c.get(Calendar.MONTH) + 1) + "_"
                            + c.get(Calendar.DAY_OF_MONTH); // january starts with 0
        config.setFileName("eMoris"
                        + "-" + title.replace(' ', '_')
                        + "-" + fileNameDate
                        + "." + logik.getFileExtensions());
        
        logik.init(exportIn, this.exportOut, config, title, layers);
        
        logik.serialisierung();
        logik.aufbereitung();

        boolean compressed = false;
        if (this.exportOut.size() > config.getSchwellenWert()) {
            try {
                final ByteArrayOutputStream newOutStream = new ByteArrayOutputStream();
                newOutStream.write(Zip.compress(this.exportOut.toByteArray(), config.getFileName()));
                this.exportOut = newOutStream;
                compressed = true;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        final SendLogik sl = (SendLogik) this.findObjectForGivenClass(
                config.getSendClass());
        new SendExport(sl).send(this.exportOut, config, compressed);
    }

2.
Code:
  * @see org.pcd.technologie.util.export.core.ExportLogik#serialisierung()
     */
    public final synchronized void serialisierung() {
        XMLProzessor process = new XMLProzessor(
                this.data,
                this.xml,
                this.config,
                this.title,
                this.layers);
        boolean columnSummary = false; // old xml version with column fields at bottom of file
        
        if (this.config.getBezeichnung().equalsIgnoreCase("SPSS")) {
           columnSummary = true; 
        }
        
        process.processXML(columnSummary);
        //this.saveFile("xml"); // debug
        
        String xsltFilepath = "";
        if (this.config.getInfoFile() == null) {
            xsltFilepath = null;
        } else if (this.config.getInfoFile().startsWith("http")) {
            xsltFilepath = this.config.getInfoFile();
        } else if (this.config.getInfoFile().contains("C:")) {
            xsltFilepath = this.config.getInfoFile();
        } else {
            ServletContext ctx = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();
            xsltFilepath = ctx.getRealPath(this.config.getInfoFile());
        }
        XMLExport.LOG.debug("new xsltFilepath for export is: [" + xsltFilepath + "]");
        
        if (xsltFilepath == null) {
            if (this.config.isManuallyCreated()) {
                // manually means print a pdf
                // which needs a xslt file to process
            	XMLExport.LOG.fatal("no xslt-file defined for manually created configuration"
            			+ "[" + this.config.getBezeichnung() + "]");
                throw new IllegalArgumentException("no xslt-file defined!");
            }
        } else {
            XSLTTransformer transformer = new XSLTTransformer();
            ByteArrayInputStream inputXml = new ByteArrayInputStream(this.xml.toByteArray());
            transformer.transform(inputXml, this.xml, xsltFilepath);
            //this.saveFile("fo"); // debug
        }
    }

3.
Code:
/**
     * Erzeugt das XML und speichert es im übergebenen xml outputstream.
     * @param columnSummary flag if columns should be summarized at the bottom of file or not
     */
    public synchronized void processXML(final boolean columnSummary) {
        Document doc = new Document();

        Element rootElement = new Element("DataTableResult");
        Namespace xsiNS = Namespace.getNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
        rootElement.addNamespaceDeclaration(xsiNS);

        if (this.validierungsFile != null) {
        rootElement.setAttribute("noNamespaceSchemaLocation",
                this.validierungsFile, Namespace.getNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance"));
        }

        Attribute attribute = new Attribute("name", this.name);
        rootElement.setAttribute(attribute);
        doc.setRootElement(rootElement);
        
        this.processHeader(rootElement);
        this.processRows(rootElement, columnSummary);
        if (columnSummary) {
            this.processDataColumns(rootElement);
        }
        
        XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());

        try {
            out.output(doc, this.xml);

            // Validierung.
            ByteArrayInputStream inp = new ByteArrayInputStream(this.xml.toByteArray());

            this.validierung(inp);
        } catch (IOException e) {
            e.printStackTrace();
            this.xml = null;
        } catch (final XmlNotValidException e) {
            System.err.println(e.getMessage());
            e.getStackTrace();
            this.xml = null;
        }
    }

4.
Code:
  /**
     * Converts an FO file to a PDF file using FOP.
     * @param inputStream the FO file
     * @param outputStream the target PDF file
     * @throws IOException In case of an I/O problem
     * @throws FOPException In case of a FOP problem
     */
    public void convertFO2PDF(final ByteArrayInputStream inputStream,
            final ByteArrayOutputStream outputStream) throws IOException, FOPException {
        try {
            final FopFactory fopFactory = FopFactory.newInstance();
            final FOUserAgent foUserAgent = fopFactory.newFOUserAgent();

            outputStream.reset();

            // Construct fop with desired output format
            final Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF,
                    foUserAgent, outputStream);

            // Setup JAXP using identity transformer
            final TransformerFactory factory = TransformerFactory.newInstance();
            // identity transformer
            final Transformer transformer = factory.newTransformer();

            // Setup input stream
            final Source src = new StreamSource(inputStream);

            // Resulting SAX events (the generated FO) must be piped through
            // to FOP
            final Result res = new SAXResult(fop.getDefaultHandler());

            // Start XSLT transformation and FOP processing
            transformer.transform(src, res);

        } catch (final Exception e) {
            Fo2Pdf.LOG.fatal("Problem with fo 2 pdf transformation: "
                    + e.getMessage());
            System.err.println("error while creating new Fo2Pdf: " + e); // FIXME delete me!
        } finally {
            outputStream.flush();
        }
    }

Da diese Komponente nicht von mir entwickelt wurde tue ich mir ein wenig schwer bei der Analyse - vllt. fällt es einem von euch leichter.

Seht ihr irgendwo ein potentielles Speicherleck?
 

thomator

Bekanntes Mitglied
Hi,
ich denke, es liegt eher an der Speicherkonfiguration des Tomcat. Die XMX und XMS-Werte werden üblicherweise auf den gleichen Wert festgesetzt. Dadurch beginnt die GarbageCollection mit dem Freiräumen des Speichers erst kurz bevor der Speicher voll ist.
Wenn dann aber noch neue Objekte entstehen, die größer sind, als der Freigeräumte Speicher kommt es zu diesen Speicherüberläufen.
Versuch mal die Werte weit genug auseinander zu legen.
Ich hatte gerade bei Lasttests das gleiche Problem, habe danach die Parameter Xmx und Xms 256MB auseinandergelegt und es hat geholfen.
 

y0dA

Top Contributor
Hi!

Naja wenn man den init und den max Wert so auseinanderlegt kann es aber auch passieren dass der Tomcat sich beim "neuen Speicher beschaffen" ebenfalls in die ewigen Jagdgründe befördert.
 

thomator

Bekanntes Mitglied
Das ist mir noch nie passiert. Wir haben für Portale in Tomcat-Umgebungen Servlets im Einsatz, die lange Zeit am Stück laufen. Die Tomcats haben Initialwerte von 1GB und max-Werte von 2GB. Und laufen absolut stabil, auch unter Stress-Bedingungen.
Warum soll das denn passieren?
 

y0dA

Top Contributor
Ich bilde mir lediglich ein so etwas einmal gelesen zu haben (google).

Da du wohl ziemlich fit bist mit Tomcat wollte ich dich noch folgendes fragen:
Wie ist das Speicherverhalten vom Tomcat, wenn nun bspw. der Tomcat 512 inital und 1024 max Wert hat und es nach einer unbestimmten Zeit (nach Durchführung etlicher schweren Lasttest) zu einer OurOfMemoryException kommt, woran liegt das dann definitiv? Existieren dann einfach zuviele nicht freigebene Objekte (auch von früheren Lasttests) noch im Tomcat Speicher? Gibt es eine Möglichkeit jene Stellen zu finden (jaja Profile - hab den JProfiler nun als Test Version installiert, jedoch sehe ich da lediglich welche Typen am meisten benötitgt werden (HashMap, LinkedList).

Was könnte der Grund sein dass ein Heap Space Error auftritt bzw wie kann ich das verhindern (einfach mal grob beschreiben wenn möglich). Sollte ich bspw nicht mehr benötigte Objekte auf NULL setzen?

Kann es sein dass die oben beschriebenen Reports einfach im Tomcat Speicher bleiben und nie freigegeben werden?

mfg
 

thomator

Bekanntes Mitglied
Hi,
also grundsätzlich sollte man schon zusehen, dass alle nicht mehr benötigten Objekte wieder freigegeben werden. Allerding geschieht das auch, wenn keine Referenzen auf das Objekt mehr existieren. Wenn Du da nicht ganz so fit bist schau Dir mal das Thema Weak-References an, da passieren häufig Fehler mit nicht freigegebenen Objekten. Definitiv festzulegen, wodurch die Speicherüberläufe zustande kommen, ist so gut wie unmöglich, ohne die kompletten Lasttest-Szenarios und den Quelltext zu kennen. Aber gerne werden bei Lasttest auch endlos Anmeldungen gefahren, ohne dass die Nutzer wieder abgemeldet werden. Wenn man dann der Session im Code noch nutzerspezifische Objekte anhängt, kann auch das Session-Handling bzw. der Session-Pool schon den Speicher sprengen.

Für das Testen von Servlet-Code gibt es von Apache ein Framework namens 'Cactus', das glaube ich auch potentielle Memory-Leaks finden kann.

Grundsätzlich musst Du aber nicht jedes Objekt explizit null setzen, sorge einfach dafür, dass die Referenzen verschwinden. Dabei wird gerne auch mal vergessen, die Referenzen aus diversen Listen/Collections zu entfernen.

Zu der Report-Geschichte:
Die Verarbeitung von XML ist eigentlich immer sehr Zeit- und Ressourcenintensiv. Sprich, der Aufbau des XML-Baums im Speicher, die entsprechenden Operationen (parsing, etc.) fressen Zeit und Speicher. Wenn Du mit Lasttests richtig viele davon parallel anstößt kann das schon zu ernsthaften Problemen führen.
Die Frage hier sollte auch sein: Wie sinnvoll ist ein Lasttest mit x Nutzern für die Generierung von Reports? Wir haben mal eine Berechnung angestellt zur Nutzung von JMeter. Das Ergebnis war, dass die Simulation von 15 Nutzern mittels JMeter ohne den Einsatz von Timern etwa einer Reallast von 600 Nutzern entspricht. Dabei wurden Ladezeiten, Clickzeiten etc. berücksichtigt. Also die Lasttests sollte man schon auch richtig dimensionieren, ansonsten bringt das nix.

So, ich hoffe das hilft Dir ein wenig weiter...

MfG
 

y0dA

Top Contributor
Hi, danke nun sind etliche Verständnislücken geschlossen.

Betreffend Weakreferences, wie darf man das verstehen? Hab zwar die SUN API dazu durchgelesen nur finde ich nirgends ein kl. Bsp. welches mir den Vorteil zeigt.

Code:
...
XMLOutputter out = new XMLOutputter(Format.getPrettyFormat()); 

        try { 
            out.output(doc, this.xml); 

            // Validierung. 
            ByteArrayInputStream inp = new ByteArrayInputStream(this.xml.toByteArray()); 

            this.validierung(inp); 
        } catch (IOException e) { 
            e.printStackTrace(); 
            this.xml = null; 
        } catch (final XmlNotValidException e) { 
            System.err.println(e.getMessage()); 
            e.getStackTrace(); 
            this.xml = null; 
        } 
    }

Hier wird "inp" neu instanziert (starke Referenz) und nicht explizit auf NULL gesetzt, demnach könnte es lange im Speicher rumlungern? Umgehung mit Weakreferences?

Betreffend Tomcat habe ich noch folgende Frage:
Wenn ich den Tomcat mit Xms512M und Xmx1024 initialisieren dann nimmt er sich immer mehr Speicher, wenn er es benötigt - nur zurückgeben tut ihr nie wieder. Sprich wenn der den initial Wert einmal überstiegen hat geht er nie wieder auf diesen Wert zurück..zumindest hab ich das so verfolgt.

mfg
 

thomator

Bekanntes Mitglied
Huhu noch mal,
zu der WeakReferences-Geschichte gibt es gute Artikel unter wiki.java.net/bin/view/Javapedia/WeakReferences
Dort sind auch mal typische Einsatzbeispiele erläutert.

Beim Tomcat ist es so, wie Du vermutest, der Speicher wird nicht wieder frei gegeben. Intern wird aber schon geräumt, so dass es dann reservierte Speicherbereiche gibt, die für den Tomcat frei sind und verwendet werden, bevor neuer Speicher reserviert wird. Ich denke, damit kann man leben...
 

y0dA

Top Contributor
Ok, lese ich mir dann mal durch.

Habe grad einen Profile über die Applikation laufen lassen und dabei ist zu sehen dass sehr sehr viele HashMaps im Speicher sind.
Frage: Kann ich in den Klassen wo eine HashMap ist eine finalize Methode machen und dort über die HashMap iterieren und alle Einträge auf null setzen - macht das Sinn oder wird das beim "löschen" der Klasse eh gemacht?
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
J Jasper Report - seltame Meldung beim compilieren Allgemeine Java-Themen 3
A Jasper Report Performance bei PDF erzeugen Allgemeine Java-Themen 0
E JUnit wie Testergebnisse pro Test ("Test Report") erhalten? Allgemeine Java-Themen 1
P Excel-Sheets erzeugen aus Report Allgemeine Java-Themen 2
C Crystal Report XI R2 Currently not implemented in the Java Reporting Component Allgemeine Java-Themen 2
S GlassFish und Jasperreports - grauer Report Allgemeine Java-Themen 3
G jasper report Allgemeine Java-Themen 3
M ireport (Jasper Report) geht nur auf meinen Rechner Allgemeine Java-Themen 3
D Report Engine gesucht Allgemeine Java-Themen 2
M Report mit Barcodes Allgemeine Java-Themen 10
B Report-Designer für Java Allgemeine Java-Themen 6
C Report erstellen Allgemeine Java-Themen 3
M Apache Proxy Weiterleitung auf Tomcat funktioniert nicht wie gewünscht Allgemeine Java-Themen 1
M tomcat probleme Allgemeine Java-Themen 1
M pfx-Zertifikat in Tomcat für SSL-Verschlüsselung nutzen Allgemeine Java-Themen 14
W JSP / Tomcat / Filter / Preprocessing Allgemeine Java-Themen 7
G Embedded Tomcat (war vs. jar) Allgemeine Java-Themen 6
R Tomcat startet nicht Allgemeine Java-Themen 1
X Tomcat checkParachute Allgemeine Java-Themen 1
X Encoding in Tomcat Allgemeine Java-Themen 2
X Performance für Tomcat / Apache optimieren Allgemeine Java-Themen 2
A Java Klasse auf Tomcat während der Laufzeit austauschen Allgemeine Java-Themen 1
N Schulung zu Tomcat/JSP/Struts gesucht Allgemeine Java-Themen 0
P Tomcat Deploy path Allgemeine Java-Themen 2
reibi Classpath Classpath Variable beim Tomcat Allgemeine Java-Themen 2
HarleyDavidson Tomcat VS Windows Scheduled Task Allgemeine Java-Themen 4
L Java Version aus Tomcat ermitteln Allgemeine Java-Themen 3
J WindowsServer (12) und Tomcat 7 Allgemeine Java-Themen 14
D Tomcat/Derby Webapp Allgemeine Java-Themen 7
2 JPA und Tomcat Allgemeine Java-Themen 4
S Tomcat java.util.logging - keine Logs Allgemeine Java-Themen 12
S Mac Adresse aus Tomcat Allgemeine Java-Themen 7
H Tomcat: JVM Crash ntdll.dll Allgemeine Java-Themen 2
I Problem mit Tomcat der URL Allgemeine Java-Themen 5
Mr.Isaaaac Tomcat Proxy Einstellungen, hä? Allgemeine Java-Themen 3
P OpenGts,Java,Ant, tomcat Allgemeine Java-Themen 8
T Wie Hibernate im Tomcat installieren? Allgemeine Java-Themen 2
E Einfaches Problem mit Tomcat Allgemeine Java-Themen 18
E welche standalone Version von Tomcat benutzen? Allgemeine Java-Themen 6
S Zwei Anwendungen unter Tomcat Allgemeine Java-Themen 4
S "Guessed User name" bei Tomcat belegen Allgemeine Java-Themen 2
G Servlet über apache Tomcat ansprechen Allgemeine Java-Themen 6
L Tomcat cache Allgemeine Java-Themen 10
L Tomcat erkennt Share nicht Allgemeine Java-Themen 6
H Tomcat VM out of memory Allgemeine Java-Themen 7
M TomCat Login Allgemeine Java-Themen 19
F Was tun bei der Exception? SW: hbernate, tomcat, postgresql Allgemeine Java-Themen 4
I Tomcat, Lucene, Probleme Allgemeine Java-Themen 4
J Suse + Tomcat + Sysdeo Plugin: Tomcat als user starten Allgemeine Java-Themen 2
franzi Tomcat acceptCount Allgemeine Java-Themen 1
G Tomcat ResourceBundle Allgemeine Java-Themen 7
V Java/Tomcat auf Virtual Server Allgemeine Java-Themen 11
M Java, PHP und Tomcat Allgemeine Java-Themen 4
P Classpath, Tomcat und Eclipse Allgemeine Java-Themen 4
M Java Webserver - Tomcat alleine oder zusammen mit Apache? Allgemeine Java-Themen 3
E Wie Java Heap Space vergrößern? Allgemeine Java-Themen 3
A Heap-Sort Allgemeine Java-Themen 2
L Java OutOfMemoryError Java heap space Allgemeine Java-Themen 3
H Änderung im maximalen heap space unter Windows 7 ?! Allgemeine Java-Themen 5
N Mögliches heap space lokalisieren Allgemeine Java-Themen 11
D Grundsätzliche Fragen zum Heap Space Allgemeine Java-Themen 12
D Datentypen Cache Images Heap Space Error Allgemeine Java-Themen 7
Thallius Wie mache ich eine Java App mit Icon startbar die mehr Heap Speicher braucht? Allgemeine Java-Themen 3
T jstat Heap(Size/Usage) PermGen(Size/Used) vs JVisual VM Allgemeine Java-Themen 2
H Frage wegen Heap-Speicher Allgemeine Java-Themen 2
L java.lang.OutOfMemoryError: Java heap space Allgemeine Java-Themen 10
R Referenzen im Heap anzeigen Allgemeine Java-Themen 3
S Compiler-Fehler Heap space! Allgemeine Java-Themen 2
V Java Heap Size -Xmx1024m reicht nicht! Allgemeine Java-Themen 14
C Method Area, Stack, Heap Allgemeine Java-Themen 7
A Umgebungsvariable Kann Heap Space nicht vergrößern Allgemeine Java-Themen 6
T Objekt 2x deserialisieren, aber nur 1x im Heap haben? Allgemeine Java-Themen 4
M *.jar >>> *.exe und "heap size" Allgemeine Java-Themen 11
E Konfigurieren des Java Heap-Spaces Allgemeine Java-Themen 5
D Java Heap error trotz anpassungen mit -xmx Allgemeine Java-Themen 4
Guybrush Threepwood Heap-Space "überwinden" Allgemeine Java-Themen 2
O Problem mit dem Heap Space (Speicherüberlauf) Allgemeine Java-Themen 12
S Java heap space zu klein? Allgemeine Java-Themen 6
A Heap in Jcreator erhöhen? Allgemeine Java-Themen 5
P Java Heap Size feststellen Allgemeine Java-Themen 6
K Heap-Volllaufen bei ArrayList<Integer> Allgemeine Java-Themen 9
B Java Heap Space Allgemeine Java-Themen 5
byte JVM Maximum Heap (Windows XP Prof. 32bit) Allgemeine Java-Themen 4
A Wie am besten Daten auslagern um heap zu schonen Allgemeine Java-Themen 4
G Probleme mit dem Java heap Allgemeine Java-Themen 14
E Heap und Comparable (warning: [unchecked] unchecked cast) Allgemeine Java-Themen 2
A OutOfMemoryError: Java heap space Allgemeine Java-Themen 11
kb22 CMS mit großen Dateien (heap problem) Allgemeine Java-Themen 3
hdi Heap Sapce Error bei sehr großem String Allgemeine Java-Themen 5
P not enough space for object heap - Trotz mehr RAM? Allgemeine Java-Themen 6
I Java heap space Allgemeine Java-Themen 3
K Erhöhung Java Heap Space in Netbeans 6.5 - funktioniert nicht oder bringt nichts? Allgemeine Java-Themen 1
S Java Heap Dump erstellen Allgemeine Java-Themen 1
T zu Beginn der main: Heap space ermitteln und hochsetzen Allgemeine Java-Themen 11
K OutOfMemoryError: Java heap space troz -Xms1024m Allgemeine Java-Themen 2
O viele Datensätze aus Datenbank - Java Heap Space - Excepion Allgemeine Java-Themen 25
V Java heap space Problem Allgemeine Java-Themen 8
V Wieso Heap Space Problem? Allgemeine Java-Themen 14
Saxony ANT, ProGuard und Java heap space Allgemeine Java-Themen 8
MQue Heap erhöhen Allgemeine Java-Themen 8

Ähnliche Java Themen

Neue Themen


Oben