Weird bad_access with dispatch_async - ios

I'm getting a really weird bad access error while using dispatch async. I managed to reduce it down to this segment of code in my program.
-(void)buttonTapped:(id)sender {
__block NSArray*foo = nil;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
//Foo was initially declared here but then moved it outside.
foo = [self someMethod];
[foo retain]; // bad access here. Why ?
dispatch_async(dispatch_get_main_queue(),0) {
// doesnt matter what happens here
}); });
}
-(id)someMethod
{
return [self secondMethod];
}
-(id)secondMethod
{
// was initially returning an autoreleased object from here. Changed it
// to eliminate that as source of the error.
id newThing = [[NSObject alloc] init];
return newThing;
}
The code didnt initially look like this but this is how it is right now . Including allocating a dummy NSObject .
How is it possible for foo to get released in between calls inside a dispatch async ? I dont understand how this is possible. I know its difficult to suggest whats going from just this but any debugging suggestions would be helpful. I tried turning on NSZombies but I dont get any Zombies.

You ask:
How is it possible for foo to get released in between calls inside a dispatch_async?
It shouldn't, unless someMethod or secondMethod are, themselves, doing something asynchronously which might allow the autorelease pool to be drained in the interim.
I tried turning on NSZombies but I dont get any Zombies.
If you've got zombies turned on and you're not getting a zombie, then I suspect the problem rests elsewhere. Frankly, I suspect that the root of the problem was eliminated in your process of simplifying the sample code for the purposes of the question:
A few other observations/clarifications:
You declared foo to be a NSArray, but then you're returning NSObject. I'll assume you meant it to be NSObject throughout.
You have a line of code that says:
dispatch_async(dispatch_get_main_queue(),0) {
I'll just assume that was a typo and that you intended:
dispatch_async(dispatch_get_main_queue(), ^{
The foo variable should definitely be inside the dispatch_async block. It doesn't really make sense to have a __block variable for something (a) you don't reference outside of that block for a block; and (b) for a block you're dispatching asynchronously.
The secondMethod should return an autorelease object, as you apparently originally had it. (Or you'd probably want to change secondMethod and someMethod to start with new in their names to avoid confusion and make life easier for yourself when you eventually move to ARC.)
If you retain the foo object, you'll want to also add the appropriate release. In fact, your original code sample returns a +1 object, and then retain it again, bumping it to +2, so you'd need two release calls.
Anyway, correcting for these various issues, I end up with the following, which does not generate an exception:
- (IBAction)buttonTapped:(id)sender
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSObject *foo = [self someMethod];
[foo retain]; // no bad access here
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"foo = %#", foo);
[foo release];
});
});
}
- (NSObject *)someMethod
{
return [self secondMethod];
}
- (NSObject *)secondMethod
{
return [[[NSObject alloc] init] autorelease];
}
Furthermore, I would suggest, especially when using manual retain and release (MRR), that you run it through the static analyzer ("Analyze" on the Xcode "Product" menu) and make sure you have a clean bill of health. (It would have pointed out some of the issues I mentioned.) It's not perfect, but it's remarkably good at identifying issues.
But, in short, the above code is fine, and if you're still getting an exception, update your question with working code that reproduces the exception.

Related

Why this simple app with ARC leaks?

So I'm relative new to objC programming. But not to C. In a more complicated app I think I have a memory leaks. I've programmed this just for make some tests. The app is very simple: it store in a MutableArray a series of integer that rappresent timers scheduled. The app has one NSTimer in the current runloop that check every second if it is the right time to ring comparing a counter with the right element of the MutableArray. Everything works, but memory in debug panel grow up, grow up, grow up…
I've try some variants but something still missing for me about ARC. I simply don't understand, since ARC is NOT a garbage collector, why memory grow and what I do wrong.
Here is the code:
-(id)initWithLabel:(UILabel *)label {
self = [super init];
self.list = [[mtAllarmList alloc]init];
self.label = label;
return self;
}
My class init function. I pass a label reference (weak beacause it is own by viewcontroller) to my class. I also allocate and init the class mtAllarmList that contain the MutableArray and other information (in the original app, file to play, volumes, eccetera).
-(void)ClockRun {
NSMethodSignature * signature = [mtClockController instanceMethodSignatureForSelector:#selector(check)];
NSInvocation * selector = [NSInvocation invocationWithMethodSignature: signature];
[selector setTarget:self];
[selector setSelector:#selector(check)];
[[NSRunLoop currentRunLoop] addTimer: self.time = [NSTimer scheduledTimerWithTimeInterval:1
invocation:selector
repeats:YES]
forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] runUntilDate:[[NSDate alloc]initWithTimeIntervalSinceNow: 30]];
}
ClockRun: is the method the app call to start everything. It simply start the timer that fires every second to check:
-(void)check {
self.counter++;
int i = [self.list check:self.counter];
if(i == 1) {
[self writeAllarmToLabel:self.label isPlayingAllarmNumber:self.counter];
}
else if (i == 2) {
[self writeAllarmToLabel:self.label theString: #"Stop"];
[self.time invalidate];
self.counter = 0;
}
else {
[self writeAllarmToLabel:self.label theString:[[NSString alloc]initWithFormat:#"controllo, %d", self.counter]];
}
NSLog(#"controllo %d", self.counter);
}
Check: simply reacts to the return value of [list check: int] methods of mtAllarmList. It returns 1 if timer must ring, 0 if not, and 2 if the sequence ends. In that case self.counter will be set to 0 and the NSTimer will be invalidate.
-(id)init {
self = [super init];
self.arrayOfAllarms = [[NSMutableArray alloc]initWithCapacity:0];
int i;
for(i=1;i<=30;++i) {
[self.arrayOfAllarms addObject: [[NSNumber alloc]initWithInt:i*1]];
}
for(NSNumber * elemento in self.arrayOfAllarms)
NSLog(#"ho creato un array con elemento %d", [elemento intValue]);
return self;
}
In mtAllarmList init method simulates the costruction an array (I've try a variety of patterns) and log all the elements.
-(int)check:(int)second {
int maxValue = [[self.arrayOfAllarms lastObject] intValue];
if(maxValue == second){
self.index = 0;
return 2;
} else {
if ([[self.arrayOfAllarms objectAtIndex:self.index] intValue] == second) {
self.index++;
return 1;
} else {
return 0;
}
}
}
Check methods instead is very elementary and I don't think needs explanations.
So, why this simple very stupid app leaks?
Since you're doing this on the main run loop, you can (and should) simplify the ClockRun method:
- (void)ClockRun {
self.time = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(check) userInfo:nil repeats:YES];
}
That NSInvocation code was unnecessary and the NSRunLoop code could only introduce problems.
Having said that, this is unlikely to be the source of your memory consumption. And nothing else in the provided code snippets looks like an obvious memory problem. If you're 100% confident that the timer is getting invalidated, then the timer is not the problem. I wonder about the object graph between the view controller at this mtClockController. Or perhaps some circular reference in view controllers (e.g. pushing from A to B and to A again). It's hard to say on the basis of what's been provided thus far.
Sadly, there's not much else we can suggest other than the routine diagnostics. First, I'd run the the app through the static analyzer (by pressing shift+command+B in Xcode, or choosing "Profile" from the Xcode "Product" menu).
Second, you should run your app through Leaks and Allocations tools to identify the what precisely is leaking on each iteration. Do you have extra instances of the view controllers? Or just the mtClockController?
Until you identify what's not being deallocated, it's hard to remedy it. And Instruments is the best tool for identifying what's not getting released. In WWDC 2012 video iOS App Performance: Memory the demonstration sections of the video give pragmatic demonstrations of using Instruments (as well as a wealth of good background info on memory management).
Third, when I've got a situation where I'm not sure if things are getting deallocated when they should, I sometimes include dealloc methods that tell me when the object is deallocated, e.g.:
- (void)dealloc {
NSLog(#"%s", __PRETTY_FUNCTION__);
}
I'd suggest this not only for your key model objects, but your view controller, too. (Sometimes we agonize over our model objects only to realize that it's the view controller, itself, which is be retained by something else.)
Clearly Instruments is a much richer tool, but this can be used to quickly identify failure to deallocate (and show you what's maintaining the strong references).
I ran you app through Instruments, watching your custom objects, and everything is being deallocated properly. Below, I marked generation A, hit the button, let the timer expire, marked generation B, hit the button again, etc. I did that four times, and I then simulated a memory warning, and did one final generation. Everything looks fine (this is a compilation of six screen snapshots in one, showing the total allocations at each of the six generations):
I inspected your Generations, as well as the Allocations themselves, and none of your objects are in there. Everything is getting released fine. The only things there are internal Cocoa objects associated with UIKit and NSString. Cocoa Touch does all sorts of caching of stuff behind the scenes that we have no control over. The reason I did that final "simulator memory warning" was to give Cocoa a chance to purge what it can (and you'll see that despite what Generations reports, the total allocations fell back down a bit).
Bottom line, your code is fine, and there is nothing to worry about here. In the future, don't worry about incidentally stuff showing up in the generations, but rather focus on (a) your classes; and (b) anything sizable. But neither of those apply here.
In fact, if you restrict Instruments to only record information for your classes with the mt prefix (you do this by stopping a recording of Instruments and tap on the "i" button on the Allocations graph and configure the "Recorded Types"), you'll see the sort of graph/generations that you were expecting:
A couple of observations:
Instead of using the invocation form of scheduledTimerWithInterval, try using the selector form directly, in this case it's a lot simpler and clearer to read.
Since you're call runUntilDate directly, I don't think you're getting any autorelease pools created/drained, which would lead to memory leakage, specifically in the check function. Either don't call runUntilDate and allow the normal run loop processing to handle things (the normal preferred mechanism) or wrap check in an #autoreleasepool block.

How to force release on iOS

I'm new to ARC but understand how it works and I'm trying it out. I'm on iOS so memory is a severe concern.
I have a MyObject class which contains lots of big data. I want to release it, and load a new set of data.
MyObject *object;
object = [[MyObject alloc] initWithData:folder1]; // load data from folder1
// later...
object = [[MyObject alloc] initWithData:folder2]; // load data from folder2
This works fine without leaks, and I'm guessing the ARC inserts a [object release] before the new assignment. My problem is the data inside 'object' is released after the new set is allocated, and I run out of memory. What I really want to be able to do is:
object = nil;
<function to pop the pool, wait till everything is deallocated>
object = [MyObject alloc] initWithData:folder2]; // load data from folder2
but I'm not sure how to do that. I could run the new allocation on a performselector afterdelay, but it feels like I'm shooting in the dark and a bit of hack. There's probably a proper way to do this?
P.S I've tried searching for an answer, but all results are about memory leaks and how to make sure variables go out of scope and set variables to nil etc. My issue isn't about that, it's more of a timing thing.
UPDATE
Thanks for the answers, I'd already tried
object = nil;
object = [MyObject alloc] initWithData:folder2];
and it hadn't worked. I wasn't sure whether it was supposed to or not. Now I understand that it is supposed to work, but I must have something else holding on to it for that fraction of a second. I have NSLogs in all of my init/dealloc methods, and I can see first all the inits of the new instances of classes (of MyObject's ivars) being called, and then almost immediately after (within a few ms), the dealloc of MyObject, followed by the deallocs of its ivars.
I also tried the #autorelease but the same thing happens.
I've searched throughout the project and pasted all the code which I think may be relevant to this.
#interface AppDelegate : UIResponder <UIApplicationDelegate>;
#property PBSoundSession *soundSession;
#end
//--------------------------------------------------------------
#implementation AppDelegate
// onTimer fired at 60Hz
-(void)onTimer:(NSTimer *) theTimer {
[oscReceiver readIncoming]; // check incoming OSC messages
// then do a bunch of stuff with _soundSession;
}
#end
//--------------------------------------------------------------
#implementation OscReceiver
-(void)readIncoming {
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
// parse all incoming messages
if(bLoadNewSoundBank) {
NSString *newFolder = parseNewFolder();
appDelegate.soundSession = nil;
appDelegate.soundSession = [MyObject alloc] initWithData:newFolder];
}
}
#end
//--------------------------------------------------------------
#implementation GuiController
// onTimer fired at 10Hz
-(void)onTimer:(NSTimer *) theTimer {
PBSoundSession *soundSession = appDelegate.soundSession;
// update gui with received values
}
#end
I thought it might be the 'soundSession' local variable in the GuiController::onTimer holding onto the old appDelegate.soundSession for the duration of that method, but to my surprise commenting out all of the GUI code (in fact disabling the timer), made no difference.
Is there a way of finding out at that point who is still holding onto my appDelegate.soundSession? I placed a breakpoint where I set it to nil, but couldn't find any useful information. I tried Instruments in Allocation template, but couldn't find anything useful there either (probably because I don't know where to look).
This is what my allocations track looks like, you can see the memory is all deallocated a bit too late!
.
This might not be an an ARC problem. What you could be seeing is your autorelease pool not draining soon enough—your MyObject is getting released, but the data it loaded is getting held onto by the pool because of some internal -retain/-autorelease pair. Try wrapping your -initWithData: calls in an #autoreleasepool block, like this:
#autoreleasepool {
object = [[MyObject alloc] initWithData:folder1];
// do things
}
// later…
#autoreleasepool {
object = [[MyObject alloc] initWitData:folder2];
// do other things
}
Setting the object to nil immediately before setting it to something else as Gabriele suggests might cause the compiler to insert the appropriate release before the second -alloc/-initWithData:, but it might be smart enough to do that already—if that doesn’t work, it’s most likely the autorelease-pool thing.
There is no delay when draining an #autoreleasepool {...}; the objects in the pool have release invoked immediately. If an object survives that, it is because there is either a strong reference elsewhere or because the object was autoreleased into the next pool out.
If you do:
a = [[Foo alloc] initBigThing];
a = nil;
a = [[Foo alloc] initBigThing];
The first instance of Foo will be released prior to the allocation of the second
With one big caveat; if any of the code paths that a is invoked upon happen to retain/autorelease it, then it'll stick around until the pool is drained. Surrounding it in #autoreleasepool{ ... }; should do the trick.
Note that the compiler will sometimes emit retain/autorelease sequences in non-optimized builds that are eliminated in optimized builds.
A bit more general answer, I found how you can force release an object:
#import <objc/message.h>
// ---
while ([[object valueForKey:#"retainCount"] integerValue] > 1) {
objc_msgSend(object, NSSelectorFromString(#"release"));
}
objc_msgSend(object, NSSelectorFromString(#"release"));
But you shouldn't do this because ARC will probably release the object later and this will cause a crash. This method should be only used in debug!

Memory management with blocks when class object is released

Assuming an example block as shown below executed.
[testBlock testPerformWithBlock:^(BOOL finished) {
if (finished) {
self.textField.text = #"Finished";
NSLog(#"Edited to add an textfield update inside block");
}
}];
What will happen if I pop the view controller that contains the object testBlock before the block returns the value of BOOL. Will the objects get deallocated properly?
Everything inside a block is retained until the block is released from memory. If the object testBlock is still executing testPerformWithBlock and the block is still alive, then everything inside the block is retained.
You are only doing an NSLog in there, so nothing will change.
However, if you do this:
if (finished) {
[self doSomething];
}
self is being used, and it will be retained, so take some caution if you are storing the blocks in some ivar somewhere
I don't understand what you are asking. There is no problem with memory management in your example. If you did not explicitly retain something, you do not need to explicitly release it.
You will get warning that strongly capturing self inside block will lead to retain cycle it will not crash but its not proper you need to do as they say strong weak dance.You can do this.
__weak typeof(self)ref=self;
^(<your bock>){
__strong typeof(ref)strongSelf=ref;
if(strongSelf)//or if(!strongSelf)return;
{
[strongSelf-><variable> methodCall];
}
};
There will be no deallocated error.
Though the retainCount of "testBlock" will not change after the invocation, the block will not be released before it runs to the end.
The result is that program will run perfectly no matters "testBlock" dealloc or not.
The sample codes following:
- (void)lazyFetchingImage:(void (^)(void))finishBlock {
[[NSOperationQueue mainQueue] addOperationWithBlock:finishBlock];
}
MainVCAppDelegate *dd = [MainVCAppDelegate new];
NSLog(#"count==%i",[dd retainCount]);
[dd lazyFetchingImage:^{
NSLog(#"22");
}];
NSLog(#"count==%i",[dd retainCount]);
[dd release];
The out put should be :
count==1
count==1
22

using variables in a block from a parallel scope

__block BOOL myBool = NO;
__strong MyClass *ptr = self;
self.footer.defaultSelectedItem.selectionBlock = ^{
myBool = YES;
ptr = nil;
};
This works just fine when my Scheme's Build Configuration is set to Debug, but I get an EXC_BAD_ACCESS when I run with Release. The EXC_BAD_ACCESS happens on the the following line
if(selectionBlock != nil) selectionBlock();
but if I comment out all the lines inside my selectionBlock then it runs with no error. Why does this run in Debug and not Release?
FYI I'm using Automatic Reference Counting (arc)
** EDIT in response to #RobNapier **
The original code that works in debug is:
__block BOOL flag = NO;
__strong EventsView *ptr = self;
self.footer.defaultSelectedItem.selectionBlock = ^{
if(flag) return;
flag = YES;
[ptr backTUI:nil];
flag = NO;
};
There's no reason for the extra ptr here. Using self inside the block would be more correct. The block will retain self in that case. That may cause a retain loop, so it's up to you to remember to set self.selectionBlock = nil at some point before dealloc to break the retain loop.
flag may be optimized away here. It's not clear how it could possibly be useful from the above code.
I'm always very nervous about long indirection-chains in a set operation like this one:
self.footer.defaultSelectedItem.selectionBlock = ...
I would make sure that footer, and the current defaultSelectedItem can't disappear before this runs.
Simplify the problem. Make the block just log "Running block." Then add back things until it crashes.
For the life of me I could not get this to work with a block. So instead I moved to using a setter for the Event View pointer. I'm guessing that fixed the problem with my pointer by setting up an additional ARC retain. I'm still uncertain because I never saw a zombie get logged when using the block so yeah.
When in doubt, use a selector.

Thread safe lazy initialization on iOS

I have a view controller that I want to lazily initialize, and once initialized, use the same copy when possible (I don't use a singleton since I do want to remove it from memory eventually), I use the getter to do so, my code look like this:
#property (retain) UIViewController *myController
...
#synthesize myController = _myController;
...
- (UIViewController *)myController
{
if (!_myController) { // Evaluation
_myController = [[MyViewController alloc] init]; // Object Creation
}
return _myController;
}
This works, but it's not thread safe, and if more than one thread evaluate to true before the object is created, I'll have a memory leak. One solution I've tried is to #synchronized the code, but I'm not sure the correct way to do it.
This appears to work, (lockForMyController is a simple NSString) but it makes this section of code a lot slower:
- (UIViewController *)myController
{
#synchronized(self.lockForMyController){
if (!_myController) {
_myController = [[MyViewController alloc] init];
}
}
return _myController;
}
I was wondering if there is some other way to achieve a lazy initialized, thread safe, property?
This solution works
Note that this solution only works if myController is accessed on a background thread the first time. It will deadlock if called on the main thread.
You want to use gcd. The key is serialize the creation of the object, so that regardless of the threads starting the block, it will always only be created exactly once.
- (UIViewController *)myController
if (_myController == nil) {
dispatch_sync(dispatch_get_main_queue(), ^ { if (_myController == nil) _myController = [[MyViewController alloc] init]; });
}
return _myController;
}
Here, even if multiple threads execute the block, the execution of the block is serialized onto the main thread and only one MyViewController can ever be created.
You won't see a performance hit here unless the object is nil.
Since the property is implicitly atomic, that means that in the setter the value will be autoreleased. This should make it suitable for mingling with your custom getting, since it will autorelease any value changes to _myController.
http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW2
However, you still may get into a race condition where you are setting the value on one thread but accessing it on another. Any time you set the value, you probably want to make sure and do something like this:
dispatch_sync(dispatch_get_main_queue(), ^ { self.myController = {newValueOrNil} });
This will make sure to serialize your setter methods calls without having to reinvent the wheel for atomic setters, which is very hard to get right.
This solution does not work
You want to use gcd.
http://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/c/func/dispatch_once
See this post about singletons. I know you don't want a singleton, but this demonstrates how to use the method. You can easily adapt it.
Create singleton using GCD's dispatch_once in Objective C

Resources