Hello all - I've been using iText for years now but I've recently been having real difficulties with it.
For years we've been using JBoss as our web server and iText as a PDF report generator and I've been quite happy with it. We recently upgraded to Java 1.5 and JBoss 4 and now I'm having memory issues. I believe I've tracked it down to iText and more specifically, Images used in iText. Here's what I'm doing: 1. I build a report using iText. 2. I build chart (which is a java BuffereredImage) that's built on the fly and is stored in memory using JFreeChart (http://www.jfree.org/jfreechart/) 3. I put the chart in a PdfPCell which is in a PdfPTable I carefully watch the memory as the PDFs are being generated, and I can clearly tell that the images are not being garbage collected. If I run the reports without images, they are perfect. All the memory that was taken while running the report is restored. However, when run with the images, memory that is claimed while generating the report is not released when finished. Depending on the size of the report, this can be quite a large amount of memory. After a few days, the servers run out of memory. Here's a memory profile while running the reports without images: Start: ~140k Peak usage while running: 175k After: 140k With images: Start: ~140k Peak usage while running: 190k After: 155k This is adversely affecting my production environment. Servers are becoming unresponsive while users are online, and they then require a reboot. Sometimes this is in the middle of the day which is really disruptive. This issue occurs with both older versions of iText and the latest... Here's my code below: public class ActivityReport { private int fontSize = 10; Color border; Font font1; Font font2; Paragraph newLine; Document document; PdfWriter writer; PdfContentByte cb; ColumnText ct; ByteArrayOutputStream baos; public ActivityReport ( HttpServletResponse response ) { try { document = new Document(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); writer = PdfWriter.getInstance(document, baos); /* create the header and add it to the document */ Phrase ph = new Phrase("Activity Report2", new Font(Font.HELVETICA, 12, Font.NORMAL, new Color(0, 0, 0))); HeaderFooter header = new HeaderFooter(ph, false); header.setAlignment(header.ALIGN_CENTER); document.setHeader(header); /* create the footer and add it to the document */ Phrase before = new Phrase("Page ", new Font(Font.HELVETICA, 8, Font.NORMAL, new Color(0, 0, 0))); Phrase after = new Phrase(". Copyright 2005, Promantek, Inc.", new Font(Font.HELVETICA, 8, Font.NORMAL, new Color(0, 0, 0))); HeaderFooter footer = new HeaderFooter(before, after); footer.setAlignment(header.ALIGN_CENTER); document.setFooter(footer); document.open(); /** * now let's add the header */ Table top = new Table(3); top.setWidth(100f); top.setBorderWidth(0); top.setDefaultCellBorderWidth(0); top.setWidths(new int[]{15,50,35}); document.add(top); addOverallChart(); Vector companies = IncentivatorsServlet.getCompany().getAllCompanies(); addCompanies( companies ); document.add( getFillerTable() ); document.close(); // write ByteArrayOutputStream to the ServletOutputStream response.setContentType("application/pdf"); response.setContentLength(baos.size()); ServletOutputStream out = response.getOutputStream(); baos.writeTo(out); out.flush(); } catch(Exception e) { System.out.println("Error in TrakStarActivityReport :runReport: " + e); e.printStackTrace(System.out); } } private void addOverallChart() { try { ...irrelevant code omitted... addDateChart( firstDateStr, logs, "Overall TrakStar Activity" ); addPageToReport( "Overall", "n/a", } catch( Exception e ) { System.out.println( "Error in TrakStarActivityReport:addOverallChart: " + e ); } } private void addCompanies( Vector companies ) { for( int i = 0; i < companies.size(); i++ ) { CompanyDataBean bean = ( CompanyDataBean ) companies.elementAt( i ); try { ... irrelevant code omitted... // add the chart of overall activity addDateChart( firstDateStr, logs, bean.getCompanyName() ); addPageToReport( bean.getCompanyName(), bean.getCompanySignUpDate(), } catch( Exception e ) { System.out.println( "Error in TrakStarActivityReport:addCompanies: " + e ); } } } private void addPageToReport( String organizationName, String renewalDate, String numActiveEmployees, String numScheduledAppraisals, String numUpcomingAppraisals, String numDelinquentAppraisals, String numCompletedAppraisals) { try { Table info = new Table(4); info.setWidth(100f); info.setBorderWidth(0); info.setDefaultCellBorderWidth(0); info.setWidths(new int[]{25,25,25, 25}); info.addCell(new Paragraph("Organization Name: ",new Font(Font.HELVETICA, fontSize, Font.NORMAL, new Color(0, 0, 0)))); info.addCell(new Paragraph(organizationName,new Font(Font.HELVETICA, fontSize, Font.NORMAL, new Color(0, 0, 0)))); ... document.add(info); document.newPage(); } catch( Exception e ) { System.out.println( "Error in TrakStar activity report: addPageToReport: " + e ); } } private void addDateChart( String firstDateStr, Hashtable values, String title ) { ... boring chart generation stuff omitteed JFreeChart chart = ...// another class generates it. //add it to the page addChartToPage( chart ); } private void addChartToPage( JFreeChart chart ) { try { PdfPTable imgTable = new PdfPTable(1); imgTable.setTotalWidth(100f); java.awt.Image img = chart.createBufferedImage( 600, 300 ); Image ixImg = Image.getInstance( img, null ); PdfPCell imgCell = new PdfPCell ( ixImg ); imgCell.setBorderWidth( 0 ); imgCell.setHorizontalAlignment( Cell.ALIGN_CENTER ); imgTable.addCell( imgCell ); if(writer.fitsPage(imgTable)) { document.add(imgTable); } else { document.newPage(); document.add(imgTable); } // attempted gc ixImg = null; img = null; chart = null; imgTable = null; document.add(getFillerTable()); } catch (Exception e) { System.out.println("error in MultiraterOverallPDF: addChartToLayout: " + e); } } private Table getFillerTable() { try { Table filler = new Table(1); filler.setWidth(100f); filler.setBorderWidth(0); filler.setDefaultCellBorderWidth(0); Cell fillCell = new Cell("\n"); fillCell.setBorderWidth(0); filler.addCell(fillCell); return filler; } catch (Exception e) { return null; } } } Hopefully this code is readable. Any feedback/help would be greatly appreciated...even beyond "greatly appreciated". It would be fantastic. Thanks in advance. David Martin ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ iText-questions mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/itext-questions Buy the iText book: http://itext.ugent.be/itext-in-action/
