Что (tf) являются секретами распределения памяти PDF (CGPDFDocumentRef)

Для чтения 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);

Это приводит к большому количеству памяти, которая, кажется, не будет выпущена после первого запуска цикла (подготовка 1-го документа), но больше неизданной памяти в дополнительных прогонах:

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 МБ), а во втором случае память достигает 20 МБ (от 7).

В обоих случаях, когда я удаляю линейную память CGContextDrawPDFPage(context, page);, (почти) постоянна на 6 МБ во время и после всех приготовлений документов.

Кто-нибудь может объяснить, что там происходит?

1 ответ

CGPDFDocument кэширует довольно агрессивно, и у вас очень мало контроля над этим, кроме как, как вы это сделали, - освобождения документа и перезагрузки его с диска.

Причина, по которой вы не видите много распределений при удалении вызова CGContextDrawPDFPage, заключается в том, что Quartz загружает ресурсы страниц лениво. Когда вы просто вызываете CGPDFDocumentGetPage, все, что происходит, это то, что он загружает некоторые базовые метаданные, такие как ограничивающие прямоугольники и аннотации (очень маленькие в памяти).

Шрифты, изображения и т.д. загружаются только тогда, когда вы на самом деле рисуете страницу, - но затем они сохраняются относительно долго во внутреннем кеше. Это делается для ускорения рендеринга, поскольку ресурсы страниц часто разделяются между несколькими страницами. Кроме того, довольно часто приходится отображать страницу несколько раз (например, при масштабировании). Вы заметите, что это значительно быстрее, чтобы сделать страницу второй раз.

licensed under cc by-sa 3.0 with attribution.