First off, a bit about how our system works:
When loading a new scene, we first load an empty scene, then check if the required AssetBundle(s) for the next scene exists locally on disk. If so, we load the required bundle/assets from disk. If not, an On Demand Resources (ODR) request is sent and we wait for the request to complete, and the necessary resources to be downloaded, before we continue on with loading the scene.
This works fine, and have been since we implemented ODR in our app.
Suddenly we found that the app crashed due to running out of memory when loading one of our bigger scenes (AssetBundles total ~350MB). We wondered about why this suddenly started happening, as it worked fine just before. We found out that any iOS device running the most recent version (iOS 9.3.1) would crash, while any device running on a lower version than 9.3 would not (we never got to test 9.3 before 9.3.1 came out).
So we started profiling using Xcode’s Instruments. More specifically the “Allocations” profiler.
The scene we’ve been testing is a scene that requires assets from an AssetBundle with a file size of 107MB.
We tested our app with two specific cases:
#1 - AssetBundles are bundled with the app as it gets installed by Xcode:
A data folder containing all our AssetBundles gets built with the app. This means that since the bundles already exist locally on the device as a scene gets loaded, we do not have to perform an ODR request to download the required assets.
What we found was that as the loading functionality starts, allocated memory is ~65MB. The app then checks for and loads the necessary AssetBundle (107MB). In real time, we see that the allocated memory increments up to ~170MB in size, the scene load finishes, and the scene gameplay starts. Allocated memory still hovering around 170MB.
#2 - AssetBundles are not bundled with the app as it gets installed by Xcode:
This of course means that since the necessary bundles does not exist locally, we perform an ODR request to download them. Same functionality as before, only that we have to wait for the ODR request to finish downloading the assets to the device before we can load them.
What we found with this setup is that as the scene loading starts, allocated memory is once again at ~65MB. The downloading of the assets starts.
We see that, just as before, allocated memory starts incrementing in Instruments. However, this time (with ODR) it doesn’t stop at ~170MB. It keeps incrementing to ~280MB of allocated memory.
At this point, the scene load seems to finish as before, but the allocated memory suddenly drops back to the “normal” amount of ~170MB, and the gameplay starts.
So from these two cases, it seems that when an ODR request/download is required, allocated memory increments to about double the amount of the size of the AssetBundle. As if the required bundle is referenced/allocated twice in memory. But this happens only on devices running iOS 9.3.1.
Summarized, our results are the following:
Device running iOS 9.2.1, without ODR:
- ~65MB of allocated memory as scene loading starts.
- Allocated memory increments up to ~170MB.
- Allocated memory stops at ~170MB
- Scene gameplay starts.
Device running iOS 9.2.1, with ODR:
- ~65MB of allocated memory as scene loading starts.
- ODR download starts.
- Allocated memory increments up to ~170MB.
- Allocated memory stops at ~170MB
- Scene gameplay starts.
Device running iOS 9.3.1, without ODR:
- ~65MB of allocated memory as scene loading starts.
- Allocated memory increments up to ~170MB.
- Allocated memory stops at ~170MB
- Scene gameplay starts.
Device running iOS 9.3.1, with ODR:
- ~65MB of allocated memory as scene loading starts.
- ODR download starts.
- Allocated memory increments up to ~280MB.
- Allocated memory drops to ~170MB
- Scene gameplay starts.
All tests are performed on Unity v5.3.4p6.
We used an iPad Air 2 and an iPad Pro for this particular test. The same crash behavior occurs on all our other devices as well (iPhone 6, iPhone 6s, iPad Mini 2).
This particular test case were carried out on one of our smaller scenes (107MB bundle size).
Just for extra information, the scene that crashes, which I mentioned earlier, requires two AssetBundles with a size of 140MB and 210MB respectively. Which means that if these sizes are in fact doubled on ODR download, it will definitely cause a crash.
.
Have anyone else experienced this or similar behavior after upgrading a device to iOS 9.3.1?
Any ideas as to what may be happening, or any tips as to what kind of workaround we may try to apply to fix this?
We haven’t come across any patch notes or seen any other posts regarding such an issue on either Apple’s or Unity’s sites/forums as of yet, so we’re kind of stumped as to what is actually happening here.
I know this may be just as relevant to post on an Apple forum, which I will as well.
Thank you for reading. Sorry for the long text and anything that may not be explained or worded properly.
Looking forward to hearing your thoughts.
EDIT: We’re using IL2CPP backend, targeting Metal/ARM64. Just ask for any other info.