About Memory Usage
PSPDFKit can deal with very complex documents, but since Android is a platform with restricted memory, and since 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 based on many factors such as device memory, manufacturer, and Android OS version. In general, more high-end devices will be able to work faster with more complex documents. However, we use a lot 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 memory on a device is free, so PSPDFKit will adapt and restrict usage when we get low memory notifications. This is normal behavior and nothing you should be worried about. However, if you’re getting lots of warnings and the system kills the app after receiving them, then you should look into the issue.
Here’s a checklist for what to look into if your device crashes and it’s related to memory pressure:
-
Are you using multiple
PdfFragment
s at once? Each one 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 (e.g. having two as a split-screen is OK, whereas showing four might be an issue). -
Set
android:largeHeap="true"
to your<application>
tag inAndroidManifest.xml
. This will create your application’s processes with a large Dalvik heap. -
Ensure you don’t have other memory leaks in your app. Google’s Memory Profiler article provides a lot of great resources.
-
Certain PDFs might simply be too complex to render. This is a rare issue, but if your PDF is really complex (and by complex, we don’t necessarily mean large), you might need to make your PDF simpler or split things across multiple pages.
-
Make sure you don’t create multiple instances of the same
PdfDocument
. For complex documents,PdfDocument
s require a considerable amount of memory, and it’s very wasteful to destroy/recreate them, especially if the document has many pages.
If you’re still encountering memory issues after following the above recommendations, try disabling certain PSPDFKit features that speed up page rendering in exchange for higher memory usage. For example:
-
Disable multithreaded rendering via
PdfActivityConfiguration.Builder#setMultithreadedRenderingEnabled()
. Multithreaded rendering speeds up document rendering by better utilizing a device’s CPU. The downside here is higher memory use when it’s enabled. -
Disable annotation overlay mode by setting
EnumSet.noneOf(AnnotationType.class)
viaPdfFragment#setOverlaidAnnotationTypes()
. Overlay mode can increase the memory footprint when viewing documents with a high number of annotations. -
Configure a smaller rendering cache size via
PdfActivityConfiguration.Builder#memoryCacheSize()
. This configuration option defaults to 25 percent of the available heap space (i.e.Runtime.getRuntime().maxMemory() / 4
). Experiment with a lower value to improve memory usage.
Memory Usage for Image Decompression
Rendering images requires them to be decompressed into memory. An image in a PDF is usually stored as a separate object (called an XObject) and contains 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.
There are far too many Android devices to list them all, but here are some popular ones and the amount of RAM available. To check the RAM of your own phone, go to Settings > About Phone.
-
Samsung Galaxy [Grand|Core] Prime [Neo Plus], Samsung Galaxy J1/S3 [Mini], Motorola Moto G: 1 GB
-
Samsung Galaxy J2/J5/J7/Grand2: 1.5 GB
-
Nexus 9, Samsung Galaxy S4/S5/A5, Samsung Galaxy Note2: 2 GB
-
Samsung Galaxy Tab S2, Samsung Galaxy Note3/4, Samsung Galaxy S6 [Edge], Google Pixel C: 3 GB
-
Samsung Galaxy Note5/7: 4 GB
-
OnePlus 3: 6 GB
(This list is roughly based on the Top Android Phones article from July 2016.)
Devices with hi-dpi (retina) screens have more pixels and thus have a higher memory consumption. For example, the Nexus 9 tablet has a screen with the resolution 2048×1536, so one fullscreen image requires 12 MB of memory.
The Android Operating System closely monitors memory usage and will terminate processes that cross the limit. Google’s documentation about managing your app’s memory is a great starting place to learn more about this. The Android ActivityManager
’s LowMemoryKiller
can be customized, so available memory might be different — even on devices with the same amount of RAM available — depending on manufacturer, user, third-party apps, and Android OS version.
When overall device memory is getting low, apps are notified. PSPDFKit correctly handles these notifications and frees up non-critical resources in such situations. This does not work if the application requests a large block of memory at once, which is what is required to decompress an image. If PSPDFKit detects an image that would require more memory than what is safe to be allocated, its logs a warning instead of taking the risk that it’s killed:
“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 so that they 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 4672*13495*4, which is equal to 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 of (pixels per inch. To learn more, read our Optimize PDF Documents for Mobile Rendering guide.