iOS can kill your application if it is using too much memory, which is what seems to be happening in your case. It is not possible for an AIR application to listen for applicationDidReceiveMemoryWarning and handle it.
As far as best practices are concerned, I can suggest the following, you might already be using them:
1) Removing event listeners,
2) Using the correct display objects - work with bitmap and use sprite if you need it etc.
3) Avoid using filters if you can.
4) If you are setting CacheAsBitmap, you should set i to true in the lowest leafs in the display list, and not on a container that has constantly moving children.
AIR 2.7 does have significant rendering improvements in CPU mode.
Hope it helps,
I have had a lot of problems trying to get my apps working on iPad1 in GPU mode, as well.
I think that you are right in pointing out that the GPU memory is probably too small for such a high-res screen on the iPad1, since it is also used for the compositing the scene (in addition to storing all the elements that make up the scene). The iPad2 by comparison has twice the amount of GPU memory and a faster GPU as well.
Another problem is that I think that the GPU memory can fill up faster than the garbage collector can clear it. When the GPU memory is full: the app will simply exit (crash), even when there is a substancial garbage collection debt, which if it had cleared, would have kept GPU memory below capacity (avoiding the crash). I think Adobe should do more to prevent this case.
Air 2.7/CPU mode works fine for me on iPad1, but not Air 2.7/GPU mode. If GPU mode is required, I have found that Air 2.6/GPU is more reliable than 2.7's on the iPad1, but I still run into GPU memory overun issues.
I am experiencing this same problem -- my app (AIR 3.1/GPU mode) frequently crashes as described by bakedbeing on the iPad1 but is stable on iPad2 and iPhone 3GS/4/4S.
The question remains unanswered:
"2: Is there any way to profile video memory usage on the iPad? Any way at all to keep tabs on the video memory?"
Per sanika, "iOS can kill your application if it is using too much memory". What, exactly, in terms of bytes, constitutes "too much memory"? Exactly how much memory, in terms of bytes, is actually available? Is there a difference between the amount of memory available to the CPU and to the GPU, or is this shared? Is AsterLUXman's theory true that garbage collection calls take longer to execute than calls which fill up GPU memory executed in the same cycle, causing these crashes? If so, is there some way to poll the amount of memory that is actually available? Considering that the crashes occur long before reaching the device's 256MB limit, is there some limit to the amount of memory that can be allocated by a single call?
Apologies if these are noob questions.
I don't know of a way to monitor GPU memory, nor video memory far that matter, on iOS apps (there may be a way on Android in debug mode, but I am not sure).
What you can do, though, is monitor system memory, via:
memory = System.totalMemory / 1048576; // in megabytes.
_debugTF.text = memory.toFixed(2).toString();
If you run this statement via an enter frame handler, you'll be able to see when the gc runs, as the mem will go back down.
Sorry, I know this isn't much help...
At time of writing, I have not yet figured out how to debug in Xcode or how to use the Xcode console. I have figured out how to run my app using Apple's "Instruments" and it seems to indicate what was already known, i.e. the iPad is running out of memory.
Exactly where it runs out of memory remains a mystery -- that number keeps changing (for reasons I don't understand) but is generally in the range of 88 - 112 MB (well short of the device's advertized 256 MB).
Right before it does, I can see a whole bunch of "Alert - Low Memory Warning" flags appear, but we have already been told that there is no way for AIR to listen for these by sanika. Why this happens on iPad1 but not on 3GS also remains a mystery.
Anyway, at this point I mostly just wish I knew how to tell Apple my app isn't supported for iPad1, so Apple could prevent people trying to buy/install it on one.
PS - I do not have a Computer Science degree, and ActionScript 3.0 is the only programming language I know. I had never used any of Apple's tools (except for "Application Loader", of course) until tarentola suggested I do so. I still know pretty much nothing about how they work, mostly because I don't speak Objective C. For instance, who is this Skyrim-villain-sounding character "Malloc"?
Unfortunately I don't have a solution for you, except to test out CPU mode if it performs well enough for you. We also tried to use GPU mode for our app and iPad 1 would often crash after sustained play. Xcode Instruments revealed that allocated memory was constantly creeping up until the critical point where the crash would occur. Using (AIR 2.7) CPU mode fixed the problem and memory usage was rock solid.
The CPU mode performance is not as great but it sufficed for our application. I never found out exactly what caused the issue in GPU mode.
Haha...Right there with you.
I think malloc stands for 'memory allocate', and it's used in the C language to request a block of memory of a particular size, for you to use as you wish. AIR does the memory management for you, which simplifies things a lot, but I guess that can also be a bad thing when you don't know what is going on.
As far as the Apple App store, unfortunately, once you've submitted an app for iPhone+iPad and they accept it, you can't go back and make it iPhone only, once you realize that it's not super stable on the iPad1. The only thing you can do at that point, short of pulling it from publication, and re-submitting 2 versions, is to optimize your app to make it stable!
A few suggestions, which have worked for me in the past:
1) Don't use GPU mode, unless you really have to. CPU can be quite fast (esp. with stage.quality = StageQuality.LOW <-- only use this once you've cached--meaning: 'rendered'--all your assets with StageQuality.MEDIUM), and it's much more stable memory-wise.
2) If duplicates of the same UI widget is used is several containers, try switching to a single--static--widget instead, and either move it to the right container when you need to (provided you don't see all containers at the same time) OR move it to the stage--depending on the situation.
3) Try to have your bitmaps point to the same bitmapData, wherever appropriate. Ex: if two buttons use the same bitmapData, but one is red and the other one yellow, just put a ColorTransform on those bitmaps, and have them point to the same (grey) bitmapData.
4) Generate graphic assets on the fly, as needed, and get rid of them when you no longer see them. There is a little framerate hit in rendering assets at runtime, but at least you are NOT occupying memory with them all the time, for stuff you only occasionaly see.
5) Use cacheAsBitmap, wherever appropriate. CAB is good in some sense bc AIR will reclaim unused CAB bitmaps that are not part of the display list at the moment. So it does its own little video memory management, enhancing stability.
I have had good results making apps stable, after quite a bit of graphical optimization.
First up, thanks to the team for AIR 2.6! It works unbelievably well for such young (on IOS) software!
We have quite a graphically rich game in development and have had a lot of success with the 3GS, iPhone 4 and iPad 2. On the iPad 1 however, we're getting an intermittent screen blackout followed by a crash back to the operating system. We're getting no flash error and no crash log.
The 3GS and the iPad 1 have the same amount of memory, and the app is crashing sometimes while using 7 MB (according to Doob Stats) and sometimes when using 14 MB, so it's not consistently a memory problem.
What is consistent however is that it crashes while putting rich menus on screen while lots of bitmaps (tiles) for our level are in memory. The iPad has unified memory usage (system and GPU ram are served by the 256MB) but a much bigger display area, so our thought is that it's probably the video memory being slammed by details, rich menus (with transparent PNGS) appearing and sucking up video ram while we still have level tiles in memory.
Our game's complete and submitted for iPhone so far, and there's a limited amount we can do about the png graphics in a tight iPad conversion turnaround period, so we're endeavouring to learn all we can about the AVM and video memory on the iPad.
We have a few questions:
1: Can running out of memory cause an app to black out and crash without any warning/explanation?
2: Is there any way to profile video memory usage on the iPad? Any way at all to keep tabs on the video memory?
3: Is there any way in AIR to listen for the iOS low memory warning? In Objective C they implement the applicationDidReceiveMemoryWarning handler function.
4: What's best practise on loading bitmaps? Will calling the myBitmap.bitmapData.dispose() function explicitly clear up video memory?
5: Will AIR 2.7 have any notable changes in usage of video memory?
6: Any other solutions in mind?
I've had exactly the issue that you describe and the solution is relatively painless. (that is if it is caused by the same coding practice I was doing)
1. Yes definately this can happen. I've even crashed the OS with my own bad code.
2. iPad has unified system and video memory. Unlike android there is no reliable way I know of to peak into what the OS thinks what memory is being used for what.
3. Don't think so sorry
4. When you are done with a bitmap it is very important that you call the dispose method on it and also it isn't a bad idea to invoke System.gc()
5. I don't think there are any major changes but if you can go with 3.0, it is better in a lot of ways
6. No other solutions. I think you are on the right track with the dispose method. It is strange to me that it is not required to dispose bitmap data inside of premade MovieClips. Raw bitmaps will get you in trouble if you don't dispose of them in a timely matter. Unfortunately we can't be as wasteful with memory on iOS as we can be on Windows. It will be a while before there are 2 gigabyte iPads.
You can test this issue for yourself on a new movie. Have a movie spawn 100 fullscreen bitmaps one at a time over a number of frames. I bet you won't get more than 60 loaded without disposing the previous ones.
Hiya guys, terrible etiquette by me, we solved (or at least discovered the nature of) this problem a while back and I really should have come back here and posted an answer for people with similar troubles.
It turns out the problem is working with stage.quality set to StageQuality.HIGH in GPU mode with rich graphics will cause the iPad AIR runtime to crash. I don't know the system-level particulars, but it's very reproducible. In GPU mode you're supposed to work in StageQuality.LOW according to what I've read - however, when you're building bitmaps from MovieClips or Sprites on the fly you need to temporarily set the quality to high or you end up with crunchy vectors and type.
An example: you want some dynamic type in there (say scores) with a drop shadow comped on a graphic, but you have a very bitmap rich app that just can't run well in CPU mode (even in AIR 2.7 and later). You draw some bitmaps in between screens (as you go to the score results) - you switch to high quality, update the text fields in a movie clip, bitmapdata.draw that movieclip so you have a flat image asset with clean type, destroy the original movieclip and then switch back to StageQuality.LOW before you display on screen.
We were leaving the stage.quality set to HIGH accidentally, and that was causing the crashes. Fix that, you fix your crashes.
Learning: be very careful with stage.quality, it will crash your app on the iPad if you leave it set to StageQuality.HIGH in GPU mode. More so on gen 1, but even gen 2.
In the interest of following up, I was also finally able to resolve the crashes using a combination advice from this page and lots of general best-practice code optimization.
- stage.quality is ALWAYS set to StageQuality.LOW while the app is running, however it is sometimes temporarily switched to StageQuality.BEST and then back to StageQuality.LOW when rendering assets assets as Bitmaps (vector Sprites, TextFields, Filters, etc.) between ENTER_FRAME events.
- The app now skimps on RAM as much as possible -- variables are recycled or manually set to null when no longer in use.
While the crashes have not been 100% eliminated, they have been drastically reduced... and as of this Friday, iPad 1 will be two generations behind anyway.
It should be noted that System.gc() appears to have no effect on memory usage whatsoever. As far as I can tell, iOS simply ignores it and only gets around to garbage collection when it feels like it.