Game crashing on 1st and 2nd Gen iPhones/iPods running 4.0 or later

Background:
In November we released LEGO Creationary to the App store. In late December we released an update with additional puzzles. The puzzles are stored in external asset bundles in the data folder of the app. There is one for the intial release (~100 puzzles) and one for the update (~35 puzzles). The packs are 2.1MB and 1.2MB in size, respectively. Inside each pack is a manifest text file (the main asset) listing the puzzles and categories and the puzzle prefabs themselves.

The Problem
Starting with the 2nd build, some people started reporting crashes on their iPod Touches. After some extensive research and debugging, we narrowed it down to a memory overrun. However, it does not occur on our 1st Gen iPod Touch still running 3.1.3 - on that it runs fine. 1st and 2nd Gen iPods and iPhones running 4.0+ seem to be the devices affected. I’m assuming this is because unlike 3.1.3, 4.0 consumes considerably more of the limited 128MB. The crash seems to consistently occur (based on debugging messaging I’ve made available) during the loading of the 2nd asset pack. Here is a screen shot of Instruments running on the device, showing the memory footprint of the app reaching around 48MB before it croaks:

Attempted Solutions

  1. We investigated increasing the requirements for the app to 3rd Generation devices and above, but this would be a bad user experience for those users who already have the app they can’t run and somewhere I read that Apple won’t allow you to updated those requirements on an existing app. We abandoned this plan before attempting it.

  2. The app starts with an initialization scene where the asset packs are loaded and made available to the game for use in future scenes. Originally, there were several art elements in this scene that I determined were probably hogging some memory because they were not optimized for these low-end devices. We re-worked this screen to have only a single, tightly-optimized image while loading. This definitely increased loading time and stability on the 3.1.3 device, but the crash still occurs on the 4.2 device.

The Head Scratching Continues…
I’m at a loss as to what to do at this point, short of re-working the asset system to split all the individual puzzles into their own asset packs and only load them on demand, which is going to be quite a lot of work and hairy to maintain. It also doesn’t jive well with our ultiamte plan of posting puzzle pack updates to a web server and having the app download them without requiring a store update. I’m already doing code stripping and all the other basic optimizations for iOS apps available in the build settings for Unity. Are there other options available to me on the XCode level, or perhaps some other method of freeing up a little more memory? Do asset bundles explode in memory when they’re loaded or is there a way to keep them compressed until something needs to be extracted?

Some loaded assets keep a prototype version of the data in memory even when no instances of the asset remain in the scene (textures are perhaps the most notable example of this). You can use Resources.UnloadUnusedAssets to free up this memory.

Awesome! That’s the kind of tip I needed to know. I ultimately solved the issue by splitting every puzzle pack into 4 puzzle packs by category (thereby reducing their size) and then externalizing the manifest files. This had the added benefit of greatly speeding up the initial launch, and the load time in-game is very low.

However…I am now experiencing some bizarre-ness where once the puzzle loads, some of the materials are missing and substituted with just plain white. Has the asset build pipeline changed from 3.0 to 3.3? I can see the prefabs still have the associated materials, but once they’re built into asset bundles and loaded into the game (both in-editor and on-device) these are missing.

Quick update, just to close this thread. The bizarre behavior I was experiencing was due to loading an asset pack, extracting a prefab from it, and immediately unloading the pack (though I told it to retain what I’d loaded). I’m not sure if:
a) I was cutting it off before it had been able to extract all the data for the model (though I thought this was synchronous, so that doesn’t really add up, and should have thrown an error).
b) The prefab was looking for the materials in the asset bundle after I’d loaded it. Once again, it should have thrown an error, rather than gracefully making every material plain white.
Either way, this kinda sucks as a workflow - I should be able to load a bundle, get what I need out of it, and then dump it to free up memory. I ultimately solved it by having the asset bundle get unloaded completely when you finish the puzzle - this didn’t seem to cause memory issues, and I was able to push my new build to the app store with no issues.