PDF内存分配(CGPDFDocumentRef)背后的秘密是什么?

7

我想为PDF阅读器准备一份文档,通过对每一页进行“截屏”并将其保存到磁盘。第一种方法是:

CGPDFDocumentRef document = CGPDFDocumentCreateWithURL((CFURLRef) someURL);
for (int i = 1; i<=pageCount; i++) 
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];      
  CGPDFPageRef page = CGPDFDocumentGetPage(document, i);
  ...//getting + manipulating graphics context etc.
  ...
  CGContextDrawPDFPage(context, page);
  ...
  UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
  ...//saving the image to disc 
  [pool drain];
}
CGPDFDocumentRelease(document);

这导致了大量的内存占用,在第一次循环(准备第一个文档)之后似乎没有被释放,但在其他循环中不再有未释放的内存:

MEMORY BEFORE:          6 MB
MEMORY DURING 1ST DOC: 40 MB
MEMORY AFTER 1ST  DOC: 25 MB 
MEMORY DURING 2ND DOC: 40 MB
MEMORY AFTER 2ND  DOC: 25 MB
....

改变代码为:
for (int i = 1; i<=pageCount; i++) 
{
  CGPDFDocumentRef document = CGPDFDocumentCreateWithURL((CFURLRef) someURL);
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];      
  CGPDFPageRef page = CGPDFDocumentGetPage(document, i);
  ...//getting + manipulating graphics context etc.
  ...
  CGContextDrawPDFPage(context, page);
  ...
  UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
  ...//saving the image to disc 
  CGPDFDocumentRelease(document);
  [pool drain];
}

将内存使用情况更改为

MEMORY BEFORE:          6 MB
MEMORY DURING 1ST DOC:  9 MB
MEMORY AFTER 1ST  DOC:  7 MB 
MEMORY DURING 2ND DOC:  9 MB
MEMORY AFTER 2ND  DOC:  7 MB
....

但显然在性能上是一步退步。

当我开始阅读PDF(稍后在不同的线程中)时,在第一种情况下不会分配更多内存(保持在25 MB),而在第二种情况下,内存增加到20 MB(从7 MB开始)。

在两种情况下,当我删除CGContextDrawPDFPage(context, page);这行代码时,内存在准备所有文档期间和之后都保持(几乎)恒定在6 MB左右。

有人能解释一下发生了什么吗?

1个回答

4

CGPDFDocument会很积极地缓存,你对此几乎没有什么控制权,除非像你所做的那样,释放文档并重新从磁盘加载。

当你删除CGContextDrawPDFPage调用时,你看不到大量的分配,原因是Quartz懒惰地加载页面资源。当你只调用CGPDFDocumentGetPage时,它仅加载一些基本元数据,如边界框和注释(在内存中非常小)。

字体、图像等仅在实际绘制页面时加载,但然后它们将被保留在内部缓存中相对较长的时间。这旨在使渲染更快,因为页面资源通常在多个页面之间共享。此外,经常多次渲染页面是相当常见的(例如,进行缩放时)。你会注意到第二次渲染页面要快得多。


谢谢,我理解了,所以我将其标记为“正确”,而没有实际证明它。 - Kai Huppmann
1
嗨omz。感谢您的详细解释。我有类似的问题,当我不断渲染页面时,内存使用量急剧增加,应用程序在一段时间后崩溃。我为每个页面(仅包含一页)使用单独的PDFDocument,在drawLayer:inContext:方法中创建和释放。请给我一个建议,以避免页面内容的自动缓存并减少内存使用量。 - Hariprasad
@Hariprasad 我和你有一个类似的问题,但我找不到任何解决方案。有些人说这是框架的错误,而其他人则认为是释放的问题,但我认为我的已经全部释放了。我没有泄漏或其他问题,但仍然会在某个时候崩溃。你找到解决方案了吗? - otakuProgrammer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接