I am experiencing memory leaks linked to NSMutableArray's in a project configured to use ARC, which I thought was supposed to handle these things for you.
The following code is triggering leaks of NSNumbers:
NSMutableArray *myArray = [[NSMutableArray alloc] init];
NSNumber *myNumber = [NSNumber numberWithFloat:10];
[myArray addObject:myNumber];
Running the last line gives the following in the debugger:
objc[1106]: Object 0x765ffe0 of class __NSCFNumber autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug
Aside from that, the object appears to be correctly added to the mutable array,
Am I doing something obvious wrong?
Note: There is one class in the project which I could not get to work with ARC, and so I excluded it from ARC using the compiler flag -fno-objc-arc. However, the leaks are occurring in other classes that are using ARC. Not sure if that is related.
Many thanks for your help.
You're probably running this code on a background thread, and don't have an autorelease pool in place. ARC will still autorelease objects for you on occasion, and if you're calling into Apple frameworks, they may still be non-ARC, so they definitely could be autoreleasing objects for you. So you still need an autorelease pool in place.
Cocoa creates an autorelease pool for you on the main thread, but doesn't do anything for you on background threads. If you're going to kick something off onto a background thread without using NSOperation or something, you'll want to wrap that thread in an #autoreleasepool, like so:
- (void)doSomething {
[self performSelectorInBackground:#selector(backgroundSomething)];
}
- (void)backgroundSomething {
#autoreleasepool {
NSLog(#"Here I am in the background, doing something.");
myArray = [[NSMutableArray alloc] init];
// etc.
}
}
Very likely you have defined the NSMutableArray as a static variable. When you do that, you fall outside the bounds of any autorelease pool, since static definitions are activated outside of any runloop. ARC is not magically, it simply automates memory management calls within the framework of the existing retain/release framework and so cannot help in those cases.
The solution is to initialize the static variable somewhere in a class so that your mutable array is built within the runloop.
Related
This is my code where I reloads particular sections of _collectionView. When I check memory leaks using Leaks template in Xcode 6.3 Instruments, it shows leak on line
[_collectionView reloadSections:indexToLoad];
and _NSCFNumber as a leaked object.
Here is my code:
NSMutableIndexSet* indexToLoad = [NSMutableIndexSet new];
for (NSInteger index in array) {
if (index != NSNotFound) {
[indexToLoad addIndex:index];
}
}
if (indexToLoad.count > 0) {
[_collectionView reloadSections:indexToLoad];
}
As I read somewhere, "the leaks instrument shows you where a leak was allocated but doesn't show you the line of code that caused the leak", how can I found a cause of leak? Also how to fix this leak?
NOTE: ARC is enabled for class in which this code is running(whole project is ARC enabled). Also this code is running on main thread.
Thanks for answers in advance :)
I notice that you are iterating an array and casing its contents to NSInteger. As you can't add NSInteger to an Objective-C array I'm going to assume that that's an array of NSNumber's which just happens to be the class which is leaking.
When you add an object (e.g. NSNumber) to a collection (i.e. NSArray, NSSet e.t.c) the collection creates a STRONG reference to that object. That means that when that NSNumber falls out of scope ARC or a garbage collector won't come along and release it. This can cause some problems however, one being retain cycles.
What I suspect is happening (I can't be sure without actually testing your full code) is that when the NSMutableIndexSet falls out of scope ARC comes along and tries to release all the NSNumber objects that it contains but finds it cannot as they are still retained by the array. If not then somewhere in code you are hanging on to one or more NSNumber instances and ARC doesn't like it.
Solution:
ARC is not a panacea when it comes to memory management. It makes memory management much more friendly and because of that people tend to assume that they can write any code they like and ARC will take care of the rest. You still need to be aware of your references (strong vs weak) and when to use each one. Also make sure you know what the default state is; for example #property NSNumber *num; is the equivalent of #property (nonatomic, strong) NSNumber *num;
I understand how Automatic Reference Counting works:
At compile time, it is determined the possible types of relationships between objects and thus where releases may occur, then at run time, the number of strong pointer references to each object is tracked and it is released when that number reaches 0. I have yet to encounter problems with this in concept or in practice, at least when dealing with the main thread.
I noticed that when I start a new background thread, it does not release any produced objects until the thread ends. I ran an example:
Essentially, an automatic '#autoreleasepool' is placed around the thread call, so it should be obvious that placing my own will not fix this issue. In fact, I have tested that with the same results. If I am correct in that, then the existence of that enforced pool is exactly causing my issue, but I assume that is the best that ARC can perform on a multithreaded application. The memory usage slowly and consistently inclines. If I leave this thread too long, the app eventually runs out of memory. This is a problem since the thread needs to be able to run indefinitely at worst.
I removed some of the main allocing in the thread already. I believe that I have determined that some of the remaining memory allocing are NSNumbers being released from an NSMutableArray because I am overwriting to it.
So I suppose I will have to do one of the following:
Remove consistent allocing in the thread altogether.
Change app to non-ARC to manually release memory in background thread.
Detect when memory is high, save the state of the thread, sync with main thread to release objects, then resume the algorithm.
Find out if there exists some way to notify the main thread or ARC that I want an object synchronized so that it may be released.
Realize that Apple actually has a way to dispatch ARC to properly handle another threads asynchronously and never said anything about it on the main reference page.
Disable ARC in the files with the alloced objects such as the dictionary. How can I disable ARC for a single file in a project?
None of those look like pretty solutions to my problem, although I may try 1 or 6. Does anyone have advice?
Update:
I ran the same algorithm but with the following autorelease blocks added to the code, at first thinking I was going to disprove rmaddy and Aaron Brager's responses.
-(void)setInt: (int)value For: (NSString *)variableName {
#autoreleasepool {
[self.intDictionary setValue:#(value) forKey:variableName];
}
}
-(void)setBool: (bool)value For: (NSString *)variableName {
#autoreleasepool {
[self.boolDictionary setValue:#(value) forKey:variableName];
}
}
Here is the resulting memory allocation graph:
They were correct. I am glad that I was wrong in this case. It means my coding is going to be a lot easier than I was starting to imagine.
Autoreleased objects are deallocated when their autorelease pool drains. This typically occurs at the end of a thread's run loop.
This behavior is the same whether you're talking about the main thread or a background thread. And of course, it only applies to objects that no longer have any strong references.
This analysis of yours is not entirely correct:
Essentially, an automatic '#autoreleasepool' is placed around the thread call, so it should be obvious that placing my own will not fix this issue.
Consider this code:
#autoreleasepool {
for (int i = 0; i < 100000; i++) {
// create an expensive autoreleased object
// do something with it
}
}
In this case, none of the autoreleased objects will be deallocated until the end of the run loop when the autorelease pool drains.
However, if you add your own autorelease pool:
#autoreleasepool {
for (int i = 0; i < 100000; i++) {
#autoreleasepool {
// create an expensive autoreleased object
// do something with it
}
}
}
The objects will be deallocated when the inner pool drains, for each iteration of the for loop.
If adding your own autorelease pool as shown above didn't resolve your issue, then the remaining possibilities are:
You are using ARC and the objects are not getting deallocated because they still have a strong reference (perhaps you have a strong reference cycle)
Your increase in memory usage is not from Objective-C objects (for example, you created a CGImageRef and never called CGImageRelease)
You are mistakenly not using ARC for this class (and you're not calling release)
Your six proposed solutions could also resolve the problem, but it's probably easier to fix than that.
I am new to IOS development and I have started to learn objective c to program towards IOS 7. and as I know, it is way easier to code now than it has been before because of the Automatic reference counting.
there are a couple of things I do not understand . in MAIN method we have the autoreleasepool block, so my first question is that in order to enable ARC , the code has to be inside this block? if no, then what is the difference between the code that is inside autoreleasepool and the rest those aren't?
my second question is that when I am writing my IPHONE programs , I have bunch of classes and non of those codes are inside "autoreleasepool" , only the code inside the MAIN method.
int main(int argc, char * argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil,
NSStringFromClass([HomepwnerAppDelegate class]));
}
}
so , does this mean that this block somehow magically gets applied to all lines of code inside any other classes of the same program?
My last question is that whether with ARC or without it, if we had a declared pointer variable inside a method, does the object gets released/destroyed when the method returns/exit?
assume we have a method like this :
- (void)doSomething {
NSMutableArray *allItems = [[NSMutableArray alloc] init];
NSString *myString = #"sample string";
[allItems addObject:myString]
}
then when we call this method and it exits, what would happen to those local variables defined inside the method ? is there any difference in the outcome if we are using ARC or not ? (Object are still in the memory or not)
Autorelease pools predate ARC by about 15 years. Cocoa uses a reference-counting memory management scheme, where (conceptually, at least) objects are created with a reference count of 1, retain increases it by 1 and release decreases the count by 1, and the object is destroyed when the count gets to 0.
A problem with this scheme is that it makes returning an object kind of awkward, because you can't release the object before you return it — if you did, it might be destroyed before the other method got to use it — but you don't want to require the other method to release the object either. This is where autorelease pools come in. An autorelease pool lets you hand an object to it, and it promises to release the object for you later. Under manual retain/release (the way we used to do things before ARC), you did this by sending autorelease to an object.
OK, so then ARC comes into the picture. The only thing that really changes with ARC is that you aren't the one writing retain, release and autorelease anymore — the compiler inserts them for you. But you still need an autorelease pool for autoreleased object to go into.
As for your second question:
My last question is that whether with ARC or without it, if we had a declared pointer variable inside a method, does the object gets released/destroyed when the method returns/exit?
assume we have a method like this :
- (void)doSomething {
NSMutableArray *allItems = [[NSMutableArray alloc] init];
NSString *myString = #"sample string";
[allItems addObject:myString]
}
then when we call this method and it exits, what would happen to those local variables defined inside the method ? is there any difference in the outcome if we are using ARC or not ?
If you're using ARC, the compiler will release any objects referenced by local variables. If you're not using ARC, you'd need write [allItems release] yourself, because the variable going out of scope does not magically cause the object it references to be released.
new to IOS development
Best not to worry, Automatic means that you mostly concentrate on other things ^)
does this mean that this block somehow magically gets applied to all lines of code inside any other classes of the same program
Yes. You're in main function, so all the code that is executed has to be inside this function - your app will terminate once it ends. Unless you create a separate thread, but it's hard to do that by accident.
the code has to be inside this block
As said above, all of your code on main thread will execute within this block.
what would happen to those local variables defined inside the method
You're guaranteed that they will be destroyed before returning.
in MAIN method we have the autoreleasepool block, so my first question is that in order to enable ARC, the code has to be inside this block? if no, then what is the difference between the code that is inside autoreleasepool and the rest those aren't?
ARC is enabled by corresponding Objective-C compiler setting. If you create a new project in the latest version of Xcode it will be enabled by default.
The #autorelease keyword places code inside the curly brackets into autorelease pool scope. Autorelease pools are used both with ARC and manual memory management.
my second question is that when I am writing my IPHONE programs , I have bunch of classes and non of those codes are inside "autoreleasepool" , only the code inside the MAIN method.
iOS applications are event based. Main thread starts event loop when you call UIApplicationMain function processing touch events, notifications etc. This event loop has its own autorelease pool that autoreleases objects at the end of the loop iteration. This autorelease pool has nothing to do with the autorelease pool you see in main function.
My last question is that whether with ARC or without it, if we had a declared pointer variable inside a method, does the object gets released/destroyed when the method returns/exit?
If you use ARC the objects will be released (unless you return a reference to an object from the method). In MMR you would need to manually send release message to destroy the objects.
I'm currently developing a game for iOS and we have a memory leak. Our project is ARC set up. I was wondering on how to ensure memory deallocation. One of the steps I was thinking of taking was convert code of the form:
-(void)methodMethod{
Object* o = [[Object alloc] init];
// Some logic
}
into:
-(void)methodMethod{
Object* o = [[Object alloc] init];
// Some logic
o = nil; // Explicit nil assignment
}
Is there a difference between the two? What other measures should I take to ensure a dealloc in an ARC setup?
We're using the Sparrow Framework.
Both methods do the same thing. Local objects are set to nil by ARC when they leave scope, so putting in a manual nil does nothing.
If you want to find a leak - you are far better off actually running it through Instruments with the Leaks tool and finding out what is being leaked, which will give you a better idea of what is going on. It's quite handy for finding retain-cycles.
As pointed out by Abizem, both methods lead to the same results, and require careful passes through Instruments. The results are not always easy to interpret.
In ARC, you should never see a leak - in the usual obj-C meaning -. Sometimes, iOS instruments can report a leak, but most if not all, this comes from the runtime, and I tend to regard them as beyond my control. What you can see however, is uncontrolled memory increase, which is typical of memory retention. Keeping strong pointers on objects is the obvious reason, which in my case has always been the consequence of : retain cycles in code blocks, and incorrect data structure cleanup, i.e. objects are created, then filled into arrays, dictionary, page control etc... but the later were not emptied properly during the app lifecycle.
Also image processing functions still use standard malloc/free directives embedded into internals UIGraphics lib, so in that case you explicitly need to free the memory (CGImageRelease, etc...). ARC will not help here.
hope this helps narrow down the problem, which as Abizem pointed out, should start with Instruments.
the following is unnecessary but (at least for me) the discussion in the comments was helpful and that's why I leave it
wrap the method in an #autoreleasepool. that will make it 99% percent sure it is being deallocated
-(void)methodMethod{
#autoreleasepool {
Object* o = [[Object alloc] init];
// Some logic
}
}
Both are the same.
A better solution to test your class:
- (void)testDealloc
{
__weak CLASS *weakReference;
#autoreleasepool {
CLASS *reference = [[CLASS alloc] init]; // or similar instance creator.
weakReference = reference;
// Test your magic here.
[...]
}
// At this point the everything is working fine, the weak reference must be nil.
XCTAssertNil(weakReference);
}
This works creating an instance to the class we want to deallocate inside #autorealase, that will be released (if we are not leaking) as soon as we exit the block. weakReference will hold the reference to the instance without retaining it, that will be set to nil.
I had developed an app and now I'm using Instruments to see the memory usage. I have a problem understanding the retain/release process of my object. This is what Instruments says:
The retain count increase when I add my object into an array, when I add it on my view and when I take off from the array.
So, when I use removeFromSuperview the object retainCount will never be zero, so the object don't release the memory.
EDIT 1:
I forgot to say i'm using ARC.
EDIT 2:
I describe exactly what happen :
I create the object together other objects in a class called NKLevelGenerator. Into it i alloc the NKIngredients and then i add all to a NSArray which will be returned. Here the retain count of every object is 2. In my NKLevelVC, my ViewController, i use this instruction :
[level addObjectsFromArray:[levelGenerator level1WithDelegate:self ciotola:ciotola bagliore:bagliore difficulty:NKDifficultyHard]];
Object level is a NSMutableArray that i alloc and init in viewDidLoad.
From here i call another method which performs this operations :
- (void)insertInArrayRandomly {
for (int i=0; i<[level count]; i++) {
[ingredienti insertObject:[level objectAtIndex:[[indexes objectAtIndex:i]integerValue]] atIndex:i];
}
}
Object ingredienti is another NSMutableArray that I alloc and init in viewDidLoad. indexes is an array of NSInteger which contains random indexes to extract NKIngredient object randomly.
Then i'm doing this :
NKIngredient *ing = [ingredienti objectAtIndex:index];
[[self view] insertSubview:ing belowSubview:navBar];
[ing animateIngredient];
[ingredienti removeObject:ing];
Before looking into Instruments have you tried the Static Analysis of your code? It may help for simple memory problems.
But the very first thing to check is: Did you follow the Golden Rule?
The Golden Rule being: For each alloc, copy or retain you must use one, and only one, releaseor autorelease.
This is the most important rule for memory management without ARC. So the fact that you object is retained by th array is none of your business, just remember what you have retained, allocated or copied and release it.
PS: Next time, your code would be much more helpful than the Instruments screenshot.
First: use instruments to see if effectively there's a memory leak, there's a tool made for this purpose and it tells you where you leak memory.
Second: it depend on how many object made [retain] on the view. If you add to an Array, it retain the view, but if you don't release it in the method that create the view, when you release the view from the array, the count will still be 1.