我正在使用itext在.NET环境中生成PDF。试图优化执行时间我正在从itextsharp 5.5.13迁移到.NET的itext 7.1.1。
生成的PDF主要包含图像。我使用多线程并行生成文档。
itext7似乎更快但内存使用率更高。由于我在同时生成多个文档,因此内存不足。
我使用相同的输入数据运行了一个简单的测试,输出文件是5 MB。下面是我的两个版本的库的代码。我的代码有问题吗?
itextsharp 5
时间:1:18,RAM:峰值173MB,然后稳定在65MB左右
public string GenerateImagesReport(IEnumerable<IChartData> data, string basename)
{
var doc = PdfUtility.CreateDoc();
string path = Shared.BuildPdfPath(basename);
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write))
{
PdfWriter writer = PdfWriter.GetInstance(doc, fs);
float left = 30f;
float bottom = PdfUtility.GetYPosition(ReportElem.Chart2);
float width = PdfUtility.CHART_WIDTH;
float heigth = PdfUtility.CHART_hEIGTH * 2 + PdfUtility.V_SPACE1 + PdfUtility.V_SPACE2 + PdfUtility.GROUP_BY;
doc.NewPage();
doc.Open();
PdfTemplate ImageTemplate;
PdfContentByte cb = writer.DirectContent;
Image img;
foreach (var chart in data)
{
// chart image
ImageTemplate = cb.CreateTemplate(width, heigth);
img = Image.GetInstance(chart.ImageBytes, true);
img.ScaleAbsolute(width, heigth);
img.SetAbsolutePosition(0, 0);
ImageTemplate.AddImage(img);
cb.AddTemplate(ImageTemplate, left, bottom);
chart.DestroyImage();
doc.NewPage();
}
doc.Close();
}
return path;
}
itext 7
时间:1:09,RAM:峰值753MB稳定到最后
public string GenerateImagesReport(IEnumerable<IChartData> data, string basename)
{
string path = Shared.BuildPdfPath(basename);
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write))
{
PdfWriter writer = new PdfWriter(fs);
var pdf = new PdfDocument(writer);
var pageSize = PageSize.LETTER;
var doc = new Document(pdf, pageSize);
float left = 30f;
float bottom = PdfUtility.GetYPosition(ReportElem.Chart2);
float width = PdfUtility.CHART_WIDTH;
float heigth = PdfUtility.CHART_hEIGTH * 2 + PdfUtility.V_SPACE1 + PdfUtility.V_SPACE2 + PdfUtility.GROUP_BY;
PdfPage page;
PdfCanvas canvas;
ImageData imgd;
Image img;
page = pdf.AddNewPage();
foreach (var chart in data)
{
canvas = new PdfCanvas(page, true);
imgd = ImageDataFactory.Create(chart.ImageBytes);
img = new Image(imgd, left, bottom);
img.ScaleAbsolute(width, heigth);
new Canvas(canvas, pdf, pageSize)
.Add(img);
chart.DestroyImage();
page = pdf.AddNewPage();
}
doc.Close();
}
return path;
}
更新
我正在使用Visual Studio Profiler来监控内存使用情况。在Yaroslav Veremenko的意见之后,我看到内存使用情况有所改善。当生成pdf的实际过程开始时,不同的图表已经标记出来。
使用itext7答案 0 :(得分:3)
我对这个库并不熟悉,但可能是PdfCanvas
和Canvas
个对象在被使用后没有被销毁,并且在文档被销毁之前一直存在于内存中。
根据文档,您必须在绘制图表后释放内存。
确保在写完后调用PdfCanvas.release() 画布。
<强> UPD 强>
我刚刚在本地运行它。在我的例子中,我有500MB的高峰。我添加后:
page.Flush(true);
它下降到250MB。
参考:http://itextsupport.com/apidocs/itext7/7.0.2/com/itextpdf/kernel/pdf/PdfPage.html#flush-boolean-
<强> UPD2 强>
使用和不使用page.Flush(true)
foreach (var chart in Enumerable.Range(0, 10))
{
canvas = new PdfCanvas(page, true);
imgd = ImageDataFactory.Create((byte[])converter.ConvertTo(data, typeof(byte[])));
img = new iText.Layout.Element.Image(imgd, left, bottom);
img.ScaleAbsolute(width, heigth);
new Canvas(canvas, pdf, pageSize)
.Add(img);
// this line has been added
page.Flush(true);
page = pdf.AddNewPage();
}
答案 1 :(得分:1)
最重要的是将PdfWriter
包裹在using
中,因为这会因为某个原因而实现IDisposable
,并且在并行使用时应该会有很大的帮助。我还删除了Canvas
的实例化,因为当您现有的PdfCanvas
对象可以做同样的事情时,它似乎是不必要的和浪费的。此外,我已将您的字段移至Foreach
范围,以便GC更有可能收集这些字段。
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write))
{
using (PdfWriter writer = new PdfWriter(fs)) //**Implements IDisposable - This should help hugely when used in Parallel**
{
var pdf = new PdfDocument(writer);
var pageSize = PageSize.LETTER;
var document = new Document(pdf);
foreach (var chart in data)
{
var page = pdf.AddNewPage(); //When it get's reassigned on the next iteration, Garbage collection will take over
PdfCanvas canvas = new PdfCanvas(page, true); //When it get's reassigned on the next iteration, Garbage collection will take over
canvas.AddImage(ImageDataFactory.Create(chart.ImageBytes), pageSize, false); //1x Less Object in Memory but you will need to play around with params for precision.
chart.DestroyImage();
}
document.Close();
}
}