iPad1 memory mystery with my texture-intensive game app - ipad

Sorry for the vague title, but not quite sure how to summarize this one.
The facts are:
I have a game that's been approved by Apple and is on the App Store.
It is a universal app. It uses textures designed for 320x480 on small screens, and uses larger textures (roughly four times as large) on retina and iPad screens.
While developing it, I would sometimes see low-memory warnings in the console log, but after reading about these it seemed like they were often somewhat spurious/unimportant, and in any event I was not having crashes, and my testers on a variety of devices (iPod Touch 2nd gen, iPod Touch 4th gen, iPhone3, iPhone4, iPad1, iPad2) were not seeing crashes.
When I started distributing the app to a wider set of beta testers through TestFlightApp, I got reports of some people seeing crashes as the app was loading, or very early after the user had chosen a level from the main menu and the app was loading the level textures. We discovered that if these users just restarted their devices, they didn't have problems any more. Since this was the first time we had seen problems like this, we attributed it to something TestFlightApp was doing, some funny state it was leaving the device in after the install (we talked to TestFlightApp about this and they had never heard of such a thing).
As stated, Apple approved the app and it's on the App Store. Soon after it went live, we got reports from some iPad1 users that it was crashing for them on app load, or soon thereafter, same kind of thing as we saw with certain TestFlightApp users. And again similar to the TestFlightApp users, these customers reported that restarting would often fix the problem. But it wasn't as nice because the problem tended to appear again. One of these users sent me several LowMemory...log files that she got off her PC after synching her iPad. There were about 10 such files, and none of them listed my program in the Processes list. Instead it showed other programs marked as either (active) or (jettisoned), and the "Largest Process" could be anything from MobileSafari to Kobo, but again my own app was never listed. So, I didn't understand that, but the bottom line seems to be that, for this user at least, something is pushing the memory over some limit where my app won't run well.
I have since gone back and talked to one of the TestFlightApp beta testers, and it turns out that he does indeed sometimes get the app crash again, so it wasn't just some residue from TestFlightApp. However, for him the crash is much less frequent than it is for this customer.
Other iPad1 testers of the game have never had any trouble. They report that they play the game for hours each day, use their iPad with several other apps in between, and rarely power it down. Similarly, I never had a crash with my iPod Touch 4th gen, which is similar to the iPad1 in the at it has a hi-res screen but only 256k RAM.
So, it's very mysterious to me what could be so different about these particular users' iPads. It's mysterious that the game works after the device is restarted, but then after some apps have been run the game (sometimes) has trouble loading. My understanding was that if my game demands memory, the OS will auto-close whatever other apps are running, as necessary, to effectively bring the amount of memory back up to the amount that's available on a freshly restarted device. My only conclusion is that after running some apps the device is left in a state where less memory is available because the OS cannot reclaim certain memory blocks or shut down certain apps.
Unfortunately I don't have one of these "misbehaving" devices to develop with. All I can think to do is try to reduce the memory needs of my app by a certain amount, and send it to one of these users who is having trouble and see if it fixes things. That seems like a potentially inefficient approach, however.
Anybody have a better idea?

Sounds like the memory spike during texture loading is what's causing the app to be terminated on some devices. It may well use less memory after everything's loaded than it does right near the end of initial loading. This could be explained by things being pushed to virtual memory, whereas direct texture loading could be bombarding the RAM with way too many allocations. My suggestions would be to:
Be more aggressive with destroying temporary data structures during loading (release a temporary structure the instant all of its useful values have been read/extracted by other things)
For autoreleased objects, keep an NSAutoreleasePool around at all times; you may even want to drain and realloc a pool several times over the course of one method if you use an exceedingly high number of autoreleased objects.
This may sound silly.. intentionally slow down your loading process. If you get rid of parallelized loads (loading multiple objects at once) or possibly insert a manual time delay in your loading thread/methods, this may give the OS more time to push things to virtual memory and thus Watchdog will not detect the app as being a RAM hog.
EDIT: One possible tactic to implement slower loading: if/when you receive a low memory warning, pause or slow loading down for a few seconds to give other apps time to lower their memory usage, then continue loading at normal speed.
Even if I'm wrong (if LowMemory...log files show Virtual+Physical usage and thus your app isn't even doing that much), I would suggest then integrating bug reporting such as QuincyKit so that you get emailed a backtrace and crash description when this bug IS encountered in the wild.

Related

iPhone restarts after API call

I am facing a very weird issue: my iPhone is restarting.
This issue occurs in a particular scenario only.
Step 1: I have a sync process in which I'm loading data for the whole app. So I'm basically doing a heavy API call by uploading 4-5 camera captured images and syncing the app data;
Step 2: After syncing, I'm pressing the iPhone home button to make the app go in background;
Step 3: I'm locking the iPhone screen(by using side button);
After a few seconds I'm seeing the apple logo and the phone seems to restart. This is not replicating when the app is connected in debug mode. I checked the debug navigator app is using only 125 MB of memory, disk and network values is 0%. Energy Impact is showing high, I'm not sure this is due to high energy impact. I'm facing this issue only on iOS 12.4.
The fact that the phone (or possibly just springboard) restarts, and not just your application means this is Apple's bug. You're not supposed to be able to crash iOS even if you try.
Finding a likely cause will be hard since the system is not behaving the way it's supposed to. The device's logs may have more information from things other than your app. This may be a system API breaking due to any number of actions from your application.
Often with this kind of thing the next OS version will fix it, but if that's not the case or it's important to track down I would try removing ways you're interaction with the system (background APIs, notifications, etc.) and see if anything fixes the issue.
If you find the problem, you may even be doing things the "correct" way according to the documentation and have to find a workaround. If you have the time you can submit a bug to Apple so the underlying issue has a better chance of being fixed.
It seems when your app is in the background and phone locked, Automatic Reference Counting (ARC) closes some connection or deallocates a resource that makes the iPhone restart. Are you closing all connections and removing all references once the upload is complete?
Phones do not spontaneously restart just because of an app’s actions. You’re having an issue with your phone, not with a program. You need to repair or replace the phone.

Why does my tvOS app eventually exit? And how can I stop it from doing that?

After noticing people in my company leaving our iPad app open all day on their desks to watch figures progress on a screen, and noticing we have some underutilized HDTVs on walls, I created a tvOS app and was able to put that information on the screen with minimal hassle, and we bought some fourth generation Apple TV units for the TVs. It's a huge hit.
However the one hitch is that the app doesn't stay alive indefinitely. I'm not sure why, but even though we've told tvOS to stay awake and not go to screen saver, every morning I come in and the app has exited and we're staring at the home screen. I have Crashlytics/Fabric installed on the app and I've had it crash a few times and send me emails about it but when I restart the app in the morning I don't get any emails, nor do I see any recurring crashes on their dashboard (it would likely be the same thing every day), so I don't think it's crashing.
So at this point it would make sense that perhaps there's some sort of time limit to how long an app can run that I'm running into.
I guess my first question is am I running into some sort of time limit at all, and the second question would be how could I prevent it from happening?
The intention is for this to only ever be an internal app and not go on the App Store so if there's some sort of way to do this that might get the app rejected by Apple that's not a problem since we're probably never going to release this to the public.
UPDATE:
So while Crashlytics/Fabric isn't telling me that the app crashed, the crash logs in the Devices window in Xcode is telling me that there are crashes.
Specifically it looks like at approximately 11:45PM every night, give or take a minute, it crashes with a EXC_BAD_ACCESS (SIGILL) KERN_PROTECTION_FAILURE message. So I'm left wondering if there's something happening fifteen minutes to midnight in tvOS, or in what my app is doing, or if it's just a grand coincidence that the memory leak or whatever that might be causing this is happening at that time.
I guess one way to test it would be to make an app that does nothing and see if the same thing happens. The lack of answers on this post makes me think this is either an issue in my code (i.e., tvOS isn't enforcing some curfew or something) or that not many people are trying to use tvOS in this way.

How to detect an OS forced App Shutdown

I am working on a iOS Application for >=iOS8 Devices. My app is memory intensive which becomes a problem since the app can crash. I have CrashLoggers in place that report crashes on the app during the next start. However there are certain scenarios when the app may consume higher than usual memory and the OS may terminate it. Is there any delegate that I could use to detect an OS forced app termination?
I tried [AppDelegate applicationWillTerminate:] and [AppDelegate applicationDidReceiveMemoryWarning:] but they are going to give me false positives for the most part. The problem is that this is not a exception, but a system signal raised by OS to kill the app that I am trying to detect within the scope of the event.
I am a new programmer. Let me know if I am understanding things incorrectly or I am making impractical assumptions.
I have read the following links:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/index.html#//apple_ref/occ/intfm/UIApplicationDelegate/applicationWillTerminate:
Is there any method in appDelegate which is called when application crashes?
I understand that preventing the problem is better than cure. But here I am trying to detect if there's going to be a problem. It's not like the app always crashes. There may be some edge case scenarios or users on very old devices like iPhone 4s/iPad Air 1 for which the app can run (possibly) into problems. So, I need a logging mechanism around this.
The runtime of the app is ~120MB worst case which is high but well under the range of too high. While the app has a lot of features, Image processing in the app is difficult to perform while maintaining the quality and also to profile in terms of memory(spikes depend on size, quality of image, lighting, etc.). So my app is well within the boundary line, and I am asking for way to detect if the app crosses this boundary when used by the user.
I totally agree with optimization(or fixing the crash) suggestion that you gave, and I would try my best to optimize(or de-bug) the app.
When app crashes or is killed by the system, there is no signal that you can catch meaningfully.
What makes you think applicationDidReceiveMemoryWarning: is giving you false warnings?
Receiving a memory warning and then not being killed is not a false positive. That just means your app didn't increase memory allocations enough to cross the threshold.
When you receive a memory warning, log if you want, but also decrease memory usage.
How do you know that the maximum runtime allocation footprint is 120MB? Depending on device, you'll have anywhere from around 125MB (iPad 1) to well over 1GB of memory available on modern devices (more on iPad Pro).
You should be getting your applicationDidReceiveMemoryWarning: called when the system is under memory pressure. This can be simulated by selecting the Simulate Memory Warning menu item in the Hardware menu.
If you actually go over your memory limit on device, you'll get jetsamed (SIGKILLed). You can't detect that.
If you want to simulate the jetsam, just send your process a SIGKILL (kill -9 <pid>)

Approach to load testing iOS app

I did a search on this but couldn't find a match, possibly due to several meanings of the phrase "load testing"... but what we are trying to do is to make sure our App (which is a medical device that MUST display updated data in a timely fashion) will process data at a required throughput, even if the iPhone gets busy -- e.g., if there are a bunch of apps open that require CPU attention.
The best test approach we can come up with is basically that... open a bunch of apps, and perhaps try to load the CPU by sending it a bunch of emails with large attachments.
But obviously that is just kind of a stab at the risk. Are there any better techniques out there, or tools? Thanks for any help.
From the perspective of your app development, you need to focus on fixing:
"What happens when data doesn't send?"
"What happens when the app gets closed by iOS for whatever reason?"
There's a million ways to create scenarios that will cause bad cases to happen. Knowing you are covered from general failure is the safest thing to rely on.
From the perspective of validating an existing app:
In past scenarios, when I haven't had control over the development of the app, I've tested these scenarios through manual exploratory testing on physical devices.
Nowadays the iPhone Simulator now provides lots of utilities so that you may not need to do this all manually. Scroll to the bottom for these answers.
Testing when the device doesn't reliably transfer data
Nontechnical way: Go on 3G and Airplane mode and toggle connectivity frequently as you use the app.
More technial way: set your phone up to proxy through your computer. Throttle the connection. Charles does this.
As you throttle the connection, use the app to do any transactions that talk to the backend.
Do they get sent correctly once you reconnect to Wi-Fi or a more stable Wireless connection?
Testing when the CPU is overloaded
Get the oldest phone that supports your highest target OS (e.g. iPhone 4S on iOS 9) and open a few games in the background.
Use your app for about 30 minutes aggressively.
By aggressively I mean, pretend to be an impatient user that taps 5 times on every button and everywhere else on the screen until you start to notice slowness.
Exploit the areas that seem to cause the slowness.
Hot spots are: animations, videos, things that cause data to go to the backend, tableviews, collection views, etc.
See what happens to the app when it crashes.
Did you get logged out?
Was any key data malformed or lost?
Using the simulator for these things
A note about using the simulator.
The simulator is a convenient way to simulate memory warnings and you can throttle your connection with Charles, or force a reboot. But the CPU will not be throttled in the same way as if you tested on a physical device.
That aside, see the below screenshots for what options are available on the simulator that might help you.
Hope this helps!

iOS device computational/memory limit

I'm working on a game for iOS, and to start a new game the following steps are followed:
The user choose the number of pieces
Each piece is created through a loop
The game starts
On the simulator I can choose as many pieces as I want, and start as many games as I want, and the app is working fine.
But on a real device (my new iPad 3), the app crashes if I choose more than 400 pieces, and also if I start (say) 3 games with 150 pieces each. I've checked with breakpoints, it crashes in different lines: sometimes creating a piece, sometimes even after the game started. Unfortunately the console is not telling me anything.
I checked the app with instruments: there are not leaks at all, and the total allocation size is at most 4 MB. And I'm logging in didReceiveMemoryWarning in my AppDelegate, but it looks like it is never called.
My question is: how should I behave to debug this? How can I understand what the computational/memory limits of a iOS device are?
If using too much memory is causing you this problem then try a NSLog in didReciveMemoryWarning. As for the memory limit I already saw a few posts here.
How much memory does iOS allow apps to use?
or
Max application memory Limit in iPad? or
iOS memory allocation - how much memory can be used in an application?
And I think I can find a few more :)

Resources