Java FOP-如何避免使用非常多的页面序列来消耗大量内存?
即使页面不包含正向引用且Java FOP-如何避免使用非常多的页面序列来消耗大量内存?,java,pdf,xsl-fo,apache-fop,Java,Pdf,Xsl Fo,Apache Fop,即使页面不包含正向引用且块非常小,如何避免FOP消耗越来越多的内存 下面是一个测试java程序,它向FOP提供一个手工制作的FO,该FO在同一个非常基本的页面序列上不断重复: Fo2Pdf.java import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.OutputStream; import java.io.PipedInputStream; import javax.xml
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 be piped through to 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 and connect the pipes
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream(in);
// Fo2Pdf - instantiate and start consuming the 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 to make sure the consumer is faster than the 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");
}
}
正如您所注意到的,一旦页面序列关闭,FOP就会将PDF写入磁盘。这意味着页面应该是?没有被记住。但是,记忆一直在增长。
对于256MB的堆大小,生成将在大约150000个页面序列处停止
为什么会发生这种情况?我怀疑,尽管有你的睡眠电话,你的制作人的工作速度比你的消费者快得多,你的管道流正在填满你的记忆。我可以想出两种方法来解决这个问题: 选项1是使用管道而不是管道流 选项2是向Fo2Pdf添加一个公共布尔pipeIsFull方法,如果in.available超过2mb,该方法将返回true。然后,如果pipeIsFull为真,主for循环将休眠500毫秒或其他任何时间 另外,减少内存消耗的一种方法是
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);
}
我不知道这会有多大的影响,它会减少几gb,但与Fo2Pdf使用的相比,这可能是微不足道的,但它不会造成伤害。我的PDF中只有3页,我面临着同样的问题。每次运行需要另一个未释放的cca 10MB。结果PDF只有100KB大,我的FOP模板有8k行。我尝试将FOP升级到最新版本,没有区别。