java - FOP - how to avoid high memory consumption with very high number of page-sequences? -
how can avoid fop consume growing amount of memory when pages not contain forward-references , < page-sequence> blocks small?
here's test java program feeds fop hand made fo repeats on , on same basic page-sequence:
fo2pdf.java
import java.io.filenotfoundexception; import java.io.fileoutputstream; import java.io.outputstream; import java.io.pipedinputstream; import javax.xml.transform.result; import javax.xml.transform.source; import javax.xml.transform.transformer; import javax.xml.transform.transformerfactory; import javax.xml.transform.sax.saxresult; import javax.xml.transform.stream.streamsource; import org.apache.fop.apps.fouseragent; import org.apache.fop.apps.fop; import org.apache.fop.apps.fopfactory; import org.apache.fop.apps.mimeconstants; import org.xml.sax.helpers.defaulthandler; public class fo2pdf implements runnable { private pipedinputstream in; public fo2pdf(pipedinputstream in) { this.in = in; } @override public void run() { // instantiate fop factory fopfactory fopfactory = fopfactory.newinstance(); fopfactory.setstrictvalidation(false); // setup output outputstream out = null; try { out = new fileoutputstream("output.pdf"); } catch (filenotfoundexception e) { e.printstacktrace(); } try { // setup user agent fouseragent useragent = fopfactory.newfouseragent(); useragent.setconservememorypolicy(true); fop fop = fopfactory.newfop(mimeconstants.mime_pdf, useragent, out); // setup jaxp using identity transformer transformerfactory factory = transformerfactory.newinstance(); transformer transformer = factory.newtransformer(); // setup input stream source src = new streamsource(in); // resulting sax events (the generated fo) must piped through fop defaulthandler defaulthandler = (defaulthandler) fop.getdefaulthandler(); result res = new saxresult(defaulthandler); // start fop processing transformer.transform(src, res); } catch (exception e) { e.printstacktrace(); } } }
feedfo.java
import java.io.ioexception; import java.io.pipedinputstream; import java.io.pipedoutputstream; public class feedfo { public static void main(string args[]) throws ioexception, interruptedexception { // instantiate , connect pipes pipedinputstream in = new pipedinputstream(); pipedoutputstream out = new pipedoutputstream(in); // fo2pdf - instantiate , start consuming stream fo2pdf fo2pdf = new fo2pdf(in); thread fo2pdfthread = new thread(fo2pdf, "fo2pdf"); fo2pdfthread.start(); /* <fo:root xmlns:fo="http://www.w3.org/1999/xsl/format"> <fo:layout-master-set> <fo:simple-page-master master-name="a4" page-width="210mm" page-height="297mm"> <fo:region-body/> </fo:simple-page-master> </fo:layout-master-set> */ out.write(("<fo:root xmlns:fo=\"http://www.w3.org/1999/xsl/format\"><fo:layout-master-set>" + "<fo:simple-page-master master-name=\"a4\" page-width=\"210mm\" page-height=\"297mm\">" + "<fo:region-body/></fo:simple-page-master></fo:layout-master-set>").getbytes()); for(int i=0; i<100000000; i++) { // sleep 3 seconds every 50000 page-sequences make sure consumer faster producer if(i % 50000 == 0) { thread.currentthread().sleep(3000); } /* <fo:page-sequence xmlns:fo="http://www.w3.org/1999/xsl/format" master-reference="a4"> <fo:flow flow-name="xsl-region-body"> <fo:block/> </fo:flow> </fo:page-sequence> */ out.write(("<fo:page-sequence xmlns:fo=\"http://www.w3.org/1999/xsl/format\" master-reference=\"a4\"><fo:flow flow-name=\"xsl-region-body\"><fo:block/></fo:flow></fo:page-sequence>").getbytes()); } out.write("</fo:root>".getbytes()); out.flush(); out.close(); fo2pdfthread.join(); system.out.println("exit"); } }
as notice, fop writes disk pdf page-sequence has been closed. means pages (should?) not being kept memory. but, memory keeps growing , growing. 256mb heap size, generation stops @ 150000 page-sequences.
why happening?
i suspect that, despite sleep
call, producer working faster consumer , piped stream filling memory. 2 ways can think of fix this:
option 1 use blockingqueue instead of piped stream.
option 2 add public boolean pipeisfull()
method fo2pdf
returns true if in.available()
exceeds, dunno, 2mb. main loop sleep 500ms or whatever if pipeisfull()
true.
also, way reduce memory consumption is
byte[] bytes = ("<fo:page-sequence xmlns:fo=\"http://www.w3.org/1999/xsl/format\" master-reference=\"a4\"><fo:flow flow-name=\"xsl-region-body\"><fo:block/></fo:flow></fo:page-sequence>").getbytes(); for(int i=0; i<100000000; i++) { ... out.write(bytes); }
i don't know how significant of impact have (it'll reduce couple gb, that's peanuts compared fo2pdf using), can't hurt.
Comments
Post a Comment