3

I've used ARC to build a fairly simple application. However, I'm running into a memory deficiency, but I can't figure out what is causing it. Since I can't clarify what is causing it, I have a few specific details and questions.

The problem ensues when I try to load a new View Controller. This view controller hosts a number of images and, when loaded, will add a 3-4 minute audio file to an AVAudioPlayer in a singleton class I have.

The problem occurs when the view controller is pushed and popped 8-10 times. When the view controller is popped, I call stop on the AVAudioPlayer and return all relevant objects (including the AVAudioPlayer instance) back to nil.

I don't really understand what could be causing the memory leak, or what else could be ravaging the device memory, but I do have a few specific questions.

When stopping the AVAudioPlayer, will that still allow for a proper release in the memory?

Will setting the AVAudioPlayer pointer to nil after calling stop prevent the system from releasing certain data from the device memory?

Shouldn't anything, in ARC, be released when the owner(s) are deallocated (I'm asking about all of the views and data in my UIViewController that gets popped off the stack)?

Are there any issues with AVFoundation or AVAudioPlayer in ARC that I should know?

Is calling stop the wrong way to end an audio session / have it be released?

EDIT: I have started using the instruments tool in order to track my allocations and leaks. There aren't any memory leaks, or so the tool says, but the application will crash, nearly regardless of the live bytes. The application will crash when the total RAM used is over 200MB (210-230MB - my device has 256MB of RAM). My new question is will the total bytes allocated (even if they're not live) affect the memory crashes? If so, how can I prevent this?

Here is an image of a run that crashed. You can see the clump of memory warnings at the end.

RileyE
  • 10,874
  • 13
  • 63
  • 106

2 Answers2

5

Q) The problem occurs when the view controller is pushed and popped 8-10 times. When the view controller is popped, I call stop on the AVAudioPlayer and return all relevant objects (including the AVAudioPlayer instance) back to nil. A) Add a dealloc method and log the dealloc, so you know nothing is retaining those, then look for these in the console:

- (void)dealloc
{
  NSLog(@"MySpecialViewController getting dealloced!");
}

if you don't see these something is retaining this object - a delegate possibly.

Q) I don't really understand what could be causing the memory leak, or what else could be ravaging the device memory, but I do have a few specific questions. A) You should be using ObjectAlloc in Instruments (and Leaks). These are really easy to use - run the project with them in the Simulator, just use the defaults, and you'll get a lot of good info right away. You can see WHAT is leaking which should really help.

Q) When stopping the AVAudioPlayer, will that still allow for a proper release in the memory? A) No. You have to set your strong ivar/property to nil (which you said you are doing). I just checked and the AVAudioPlayer does not retain the delegate. That said, as a general rule, when I am shutting down anything its:

[something stop/cancel/etc]; 
something.delegate = nil; 
something = nil;

Will setting the AVAudioPlayer pointer to nil after calling stop prevent the system from releasing certain data from the device memory?

Q) Shouldn't anything, in ARC, be released when the owner(s) are deallocated (I'm asking about all of the views and data in my UIViewController that gets popped off the stack)? A) If the only thing that is retaining the ViewController, for instance the navigationController's viewControllers array, then yes, your viewController subclass should get dealloced, and all strong properties and ivars will too.

Q) Are there any issues with AVFoundation or AVAudioPlayer in ARC that I should know? A) I know of none, and since this is a popular class expect your problem is in your code.

Q) Is calling stop the wrong way to end an audio session / have it be released? A) If it were me:

[avPlayer stop];
avPlayer.delegate = nil;
avPlayer = nil;

EDIT: If you are getting memory warnings when your app is running, you are leaking or consuming some huge amounts of memory. Put a breakpoint where you get this warning, stop your app, and look at your allocations. I've never gotten a memory warning for real (I use ARC exclusively)

David H
  • 40,852
  • 12
  • 92
  • 138
  • 5
    @KendallHelmstetterGelner Then why do I have tens of them in my ARC app now in the store for 3 months? Apps can still get dealloc - for last minute clean up. What you cannot do is "[super dealloc];" – David H Sep 03 '12 at 20:15
  • I'm using the instruments tool (which I didn't know about, so thank you so much for that!) and there aren't any leaks. The memory, however, does increase ever so slightly over time. I don't know how to trace the objects that hold the highest "live bytes", so I don't know where the issue is. I do have an unnamed malloc at 18MB when the application crashes, but I don't think that is the cause of the crash, since the device has 256MB of RAM and it sits at 18MB while the application still runs. Maybe I'm not releasing the delegates properly. Any suggestions? – RileyE Sep 03 '12 at 21:24
  • So, does the RAM have to do with overall bytes? Shouldn't it only deal with live/delta bytes? I started receiving memory warnings while my live byte allocations were below 4MB, which is still fairly high, but I've had applications run much higher without any issues. What could be the problem? – RileyE Sep 03 '12 at 21:34
  • 1
    http://www.learn-cocos2d.com/2011/11/everything-know-about-arc/#overriding-dealloc – xyzzycoder Sep 03 '12 at 21:40
  • @David: Good point, forgot it was [super dealloc] you could not do. Sorry about the confusion. – Kendall Helmstetter Gelner Sep 04 '12 at 02:59
  • @RileyE there are other ways to consume memory besides direct allocations - mmap (which iOS often uses when loading images), and the file system cache. Both use the Unified Buffer Pool. I've posted routines on SO (as have others) that let you view the total memory consumption iOS tags you with - you could try printing that number out. Also, Core Data could be eating memory, especially if you do not use SQL as the backing store. I have a demo app on github that loads up 18000 x 18000 pixel images and never gets memory warnings. – David H Sep 12 '12 at 12:57
  • @DavidH Have you written that somewhere easily accessible? I would love to read about it, but I can't tell which of your answers it might fall under. – RileyE Sep 12 '12 at 14:42
0

One area where it is easy to run into memory trouble while using ARC is situations where you are interacting with a Cocoa Touch API that requires the main thread from a background thread.

It doesn't sound like you are up against this, but if you start seeing inconsistent behavior (e.g. what appear to be random crashes, objects going out of scope prematurely, etc.) it is worth investing some effort to see if you are interacting with Cocoa Touch from a background thread.

Sometimes callbacks from Cocoa Touch (that one might assume would be on the main thread) aren't (we have seen this in some Game Center API's).

xyzzycoder
  • 1,831
  • 13
  • 19