8

I can't figure out why iOS is terminating my app (iPad, iOS 4) due to memory usage even after I free a ton of memory in response to low-memory warnings. For example, here's a typical termination scenario, with me logging memory usage every so often -- look at the "app" usage, the first KB value on each line:

...
2011-12-14 13:25:42.343 Oyster[211:707] Memory usage (KB): app 268256, delta 6472, used 366800/373940
2011-12-14 13:25:43.292 Oyster[211:707] Memory usage (KB): app 273900, delta 5644, used 372444/381024
2011-12-14 13:25:44.159 Oyster[211:707] Memory usage (KB): app 282920, delta 9020, used 381464/389116
2011-12-14 13:25:45.184 Oyster[211:707] Memory usage (KB): app 272140, delta -10780, used 370684/379432
2011-12-14 13:25:46.109 Oyster[211:707] Memory usage (KB): app 260412, delta -11728, used 358956/365900
2011-12-14 13:25:48.443 Oyster[211:707] Received memory warning. Level=2
2011-12-14 13:25:48.454 Oyster[211:707] Memory usage (KB): app 9172, delta -251240, used 107716/112548
(gdb)

You can see app memory usage increasing till it gets a memory warning. Then I correctly respond to the memory warning and free a bunch (250MB!) of memory. At that point my app is terminated and iOS goes to the iPad home screen.

The "Memory usage" logs here are displayed with my logMemoryUsage() function which is based on code from this answer.

For the record, I'm using SDWebImage to cache UIImages in memory, but as shown, it handles memory warnings by emptying its cache (rather large at this point). I realize I could tweak SDWebImage's caching to not fill all available memory and just wait for memory warnings, but that begs the following question...

Why is iOS terminating my app, even though I'm responding to memory warnings by happily freeing a ton of memory?

Community
  • 1
  • 1
Ben Hoyt
  • 10,694
  • 5
  • 60
  • 84
  • 5
    Please include the termination log. There may be an unrelated bug elsewhere. – PengOne Dec 14 '11 at 19:11
  • What is the "termination log", and how do I view it? – Ben Hoyt Dec 14 '11 at 19:14
  • Turn on the debugger. When the app crashes, the console should have a message along the lines of "App terminating due to..." – PengOne Dec 14 '11 at 19:17
  • I am in the Xcode debugger. There's no message at all after "(gdb)" -- that's the last console log. Is there something more I need to enable? – Ben Hoyt Dec 14 '11 at 19:21
  • use allocations in instruments, simulate a memory warning, check that the memory is indeed being released... – Daniel Dec 14 '11 at 20:03
  • @Daniel, memory is definitely being freed as expected. You can see that from the decrease in app usage after the warning in the logs above, but I've also confirmed it with Profile/Allocations. – Ben Hoyt Dec 14 '11 at 20:14
  • If you get the (gdb) prompt, then your program has received some signal or exception. There should be a marker at the right end of the line (in the source window) where your program has stopped, and there should be a stack traceback in the Debug navigator (left panel). – rob mayoff Dec 14 '11 at 21:18
  • @rob mayoff, unfortunately with what I'm getting Xcode/gdb *thinks* the app is still running, but it's not (iOS has terminated it) -- so I don't get a termination log, and there's no breakpoint and no stack trace. – Ben Hoyt Dec 14 '11 at 21:41
  • Are you releasing anything yourself in response to the memory warning? It sounds like your app is crashing — probably due to dangling references to something that was released — rather than being terminated. – Chuck Dec 14 '11 at 22:36
  • @Chuck, I'm not explicitly releasing anything -- SDWebImage is doing that. It's definitely a termination, as I can download the LowMemory "jettisoned" crash logs from my iPad. – Ben Hoyt Dec 16 '11 at 19:35
  • I've got some suspicion that iOS contains an algorithm that kills an app if it detects the app doing "run-away" allocations -- too many allocations in too short a time. Hard to say how such an algorithm would work, but it's seeming to me that maybe an app can get terminated without warning if it allocates several MB of small objects in a short period of time. – Hot Licks Dec 16 '11 at 19:55
  • Try to assign nil, after usage of variables, which are not in used.Such as variable which holds images etc. – Rohit Dhawan Dec 23 '11 at 05:08

5 Answers5

11

This is kind of a general answer for good practices wrt memory management etc. Generally, sounds like the in-memory cache is simply getting way too big and even though it releases objects in response to memory warnings, by that time it's too late.

  1. Memory warnings are not inherently "bad" and you cannot avoid them. They are a normal part of an iOS life cycle and you must handle them correctly by releasing all non-essential data in all of your objects to assure your app behaves responsibly. Even if your app has a small footprint you could still get a memory warning b/c of other conditions on the device in question (e.g. other apps in use, etc). I'm referring to the runtime notification UIApplicationDidReceiveMemoryWarningNotification here. The debugger messages (e.g. "Received memory warning. Level=2") are specific to your app though they don't necessarily correlate to receiving a runtime notification.

  2. I don't know much about SDWebCache. I would look at the implementation and ensure it is efficiently releasing memory. For example, maybe using @autoreleasepool in relevant places would help it release objects more efficiently within a run loop.

  3. You should strive to keep your app's in-memory footprint is as constrained as possible. it's fine to use an in-memory cache for image data but I would limit its size. If your app's footprint gets > 250MB I'm not surprised it is being terminated, even if you handle memory warnings. It's likely too late by then.

  4. Your could have other issues causing/contributing to the termination. As the comments have suggested, you need to do more debugging in instruments to look for leaks, bad access, etc. Posting the crash log here would be helpful.

XJones
  • 21,959
  • 10
  • 67
  • 82
  • +1 for #3. There are times when it's too late. Memory warnings are delivered via IPC, and there's latency. 250MB is a LOT. I'd be willing to bet that it's 'too late.' – ipmcc Dec 23 '11 at 18:16
  • @ipmcc, out of interest, is the fact that memory warnings are delivered via IPC documented somewhere, or do you know that from public source code or some other reason? – Ben Hoyt Dec 27 '11 at 16:43
  • You can see using the debugger (details beyond the scope of an SO comment) that memory warnings arrive in the form of a mach message (i.e. IPC,) which gets turned into a main thread dispatch operation, which ends up firing the app-level notification. The details aren't documented anywhere that I can find. On top of that, it doesn't matter; If the warnings were coming from inside your process, they would still be asynchronous with respect to the kill which is coming from outside your process. Net result: it's asynchronous regardless, and there'll be latency you can't control/account for. – ipmcc Dec 27 '11 at 18:34
  • Worth noting that memory held by OpenGL is not included in allocations in XCode profiler/instruments. However, you can see it affecting the "Memory Monitor" instrument. I kept having crashes too despite freeing some allocations, because textures were being leaked. – Brent Jul 02 '13 at 20:11
1

Without more information I can't know if these apply to you, but I have commonly run into certain issues after trying to clean up memory warnings:

  • Unknown circular references prevent the memory from being freed like you expect. Use Instruments to look for them. I recently fixed a case in which I was accidentally using self within a block, causing a retain. We noticed it when there was a memory warning, and we couldn't recover from the warning well by releasing that resource.
  • Cleaning up resources – or an automatic release of resources – has released something that is still needed. You may have a nil where you do not expect one, or you may operate on a zombie. Check your retention and clean-up, especially the nilling of delegates. Turn on zombies and an exception breakpoint.

Usually the best resolution is to prevent the memory warning from occurring in the first place.

Peter DeWeese
  • 18,141
  • 8
  • 79
  • 101
  • Thanks for the help (upvoted), however, it's neither of these things: 1) you can see the app's memory usage actually going way down when I free stuff, and 2) it's not a zombie problem, as iOS is definitely terminating me (I can download the LowMemory "jettisoned" crash logs from my iPad). – Ben Hoyt Dec 16 '11 at 19:38
1

Check the code for image transformation. There is some code in the SDWebImage project which is used for scaling down the image that applies some transformation & rotation techniques on the image selected.It actually doesnt used so much to scale down the size but sometimes it cause raise the memory warning. Comment that code & try to build your Application.

I had the same problem in my app. I had tried to comment the code of transformation. Problem got resolved. You may also give a try.

iCreative
  • 1,499
  • 1
  • 9
  • 22
1

A Level 2 memory warning is Urgent. Your app probably receives one or several level 1 warnings before receiving a level 2 warning, and you should act at that moment.

In my experience, when your app receives a level 2 warning it's almost always too late, and it's going to be killed anyway.

n-b
  • 929
  • 4
  • 6
1

When dealing with large images (4Mb per image) you may run the risk of running out of memory without ever receiving a low memory warning.

The best is really to prevent your memory usage from growing too much. Loading speed of images is such that caching is good but not really necessary. It's much better to keep usage down by releasing memory as soon as you don't use it anymore.

Good luck and let us know if you find something worth sharing.

MiKL
  • 1,850
  • 1
  • 15
  • 23