代码之家  ›  专栏  ›  技术社区  ›  sillo01

为什么使用itext7。NET使用的内存比itextsharp5多得多?

  •  3
  • sillo01  · 技术社区  · 7 年前

    我正在使用itext在上生成PDF。NET环境。为了优化执行时间,我正在从itextsharp 5.5.13迁移到itext 7.1.1 for。网

    生成的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监视内存使用情况。在雅罗斯拉夫·维列门科(YaroslavVeremenko)的输入之后,我看到内存使用情况有所改善。不同的图表标记了生成pdf的实际过程何时开始。

    使用itextsharp 0:43 itextsharp memory usage

    使用itext7 0:26 itext7 memory usage

    使用itext7-第页。刷新()0:42 itext7 memory usage 2

    2 回复  |  直到 7 年前
        1
  •  4
  •   Yaroslav Veremenko    7 年前

    我对图书馆不熟悉,但可能是 PdfCanvas Canvas 对象在使用后未被销毁,并且在文档销毁之前一直保存在内存中。 根据文档,绘制图表后必须释放内存。

    确保致电PdfCanvas。完成写入后释放() 画布。

    资料来源: https://github.com/itext/itext7-dotnet/blob/dd5c209cff35c137ed451fef6e11a96889a52fe9/itext/itext.kernel/itext/kernel/pdf/canvas/PdfCanvas.cs#L69

    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();
        }
    

    graph

        2
  •  1
  •   Kitson88    7 年前

    最重要的是包装 PdfWriter 在a中 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();
        }
    }