About Memory Usage
PSPDFKit can deal with very complex documents, but since iOS is a platform with restricted memory and rendering PDFs can be quite a memory consuming task, there are certain limits in what you can do before the OS is going to kill the app. The limits are fluid per device - an iPad 2 will have more trouble with a 50k page document than the iPad Pro. However, we're using a significant amount of custom code so that old devices still work fine.
Note that PSPDFKit has been designed to use a lot of memory for caching and to make things more fluid. We don't know how much is available, so PSPDFKit will adapt and restrict usage when we get low memory notifications. This is a normal behavior and nothing you should be worried about. However, if you're getting lots and lots of warnings and the system will kill the app thereafter, then you should look into the issue.
Here's a checklist what you can do if you get crashes related to memory pressure:
Are you using multiple
PSPDFViewControllers at once? Each controller takes a considerable amount of memory, so keeping multiple ones on the screen at the same time can put a lot of memory pressure on the system. We suggest not using more than two at the same time (so two as a split-screen is ok, showing four might be an issue)
PSPDFKit.sharedInstance[@"com.pspdfkit.low-memory-mode"] = @YESin your AppDelegate, before you use any PSPDF* code. This will limit memory usage in PSPDFKit but might also slow down rendering a bit. It's often a workable solution though.
Ensure you don't have other memory leaks or retain cycles in your app. Instruments is very helpful in finding those.
Certain PDFs might be too complex to render. This is a rare issue, but if your PDF is really complex (although this doesn't necessarily mean large), then you might need to make your PDF simpler or split things across multiple pages.
If your PDF has an unusual aspect ratio (like 20k pixels long) and you use
fitToWidthEnabled, this might be an issue as well. Try disabling this property.
Saving can take up a considerable amount of memory if you have a few thousand annotations (remember that links are annotations as well). If so, make sure that background saving is disabled.
Make sure that you don't create multiple instances of the same
PSPDFDocument. For complex documents, those objects manage a considerable amount of memory and it's very wasteful to destroy/recreate them, especially if the document has many pages. Better use a global manager or use something like the
PSPDFDocumentPickerControllerthat only creates instances if they don't yet exist. Then again, very complex documents might have lots and lots of annotations, so you might also have better results if you destroy any old documents once you no longer show them.
PSPDFDocumentwith only one file-based source takes up less memory than having multiple files as backend. Using
datais the worst thing, memory-wise. If you require to use data because of encryption, use a
PSPDFDataProviderinstead, where you can decrypt/make available only those parts that are currently needed.
Memory usage for Image decompressing
Rendering images requires them to be decompressed into memory. Images in PDF are usually stored as separate objects (called "XObject") and contain the raw binary data. This data can be compressed as JPEG, JBIG2, JPEG2000/JPX, RAW or various other supported formats). Before images can be rendered, this data needs to be loaded and decompressed into memory.
For example, let's look at an image that is 4000x3000 pixels large and saved with colors. This would result in following memory usage:
memory_used = 4 * width * height 4*4000*3000/1024 = ~45.77 MB.
Why 4? ARGB is the most common way to save images, so there are 4 bytes required for every pixel.
This is more of an issue on mobile devices, where no swap space exists. Thus, there's a hard limit on the available amount of memory, which also has to be shared with other applications and the operating system itself.
Here's a quick overview of the available RAM on iOS Devices. (Unsupported devices have been omitted, see Wikipedia for a full listing)
- iPad 2, iPad Mini, iPhone 4s, iPod Touch 5: 512 MB
- iPad 3, iPad 4, iPad Air, iPad Mini 2, iPad Mini 3, iPhone 5[c|s], iPhone 6 [Plus], iPod Touch 6: 1 GB
- iPad Air 2, iPad Mini 2, iPad Pro 1 9.7-inch, iPhone 6s [Plus], iPhone SE: 2 GB
- iPad Pro 1 12.9-inch: 4 GB
Apple's iOS Operating System closely monitors memory usage and will terminate processes that cross the limit. Apple's TN2151 explains the various reasons for processes to be jettisoned. There is no actual documentation on how much memory a single process can actually use. Apple relies on a system where low memory notifications are sent so the application can free up resources in such situations. This does not work if the application requests a large block of memory at once, which is what's required to decompress an image.
The actual amount of memory that can be used is not documented but varies based on device and iOS version, as well as app type. The limit is much lower for App Extensions.
As an SDK, we set on a moderate and safe limit based on experimentation and experience over the years. This can be tricky, as this also depends on your application code and how much memory is being used there. For example, if you use frameworks like SpriteKit or OpenGL or embedded web views, these also have a high memory cost.
Devices with hi-dpi ("retina") screen have more pixels and, thus, have a higher memory. For example most iPads have 2048×1536 as resolution, so one full-screen image requires 12 MB of memory.
If PSPDFKit detects an image that would require more memory than what is safe to be allocated, we log a warning, instead of taking the risk to be jettisoned. Apple's native iOS renderer has no such precautions and when trying to render a too complex PDF, the application often just exits.
"Couldn't load image: image size too big (X bytes, maximum allowed is X)"
Adobe Acrobat has an Optimize... feature that allows you to recompress images to take up less space. Note that the raw image size can still be very large, even though in the PDF the image appears to be downscaled and small. Use Edit->Preflight... and then select the "List page objects" option.
For example, here is a PDF that has an image with 4672x13495 pixels, taking up 4672134954 = 240,5 MB.
You can use the PDF Optimizer feature of Adobe Acrobat Pro (File -> Save as Other -> Optimized PDF...) to reduce the image size (ppi, Pixels per inch. To learn more, read our Optimize PDF for mobile rendering article.