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;
Related
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.
I have a pool of objects I keep inside an NSMutableArray so if any other objects want to reference them instead of creating new objects I will simply give it a reference to an object I have already created.
In the past I would monitor retain/release calls on these objects, and when they reached a retain count of 1 (my array only) I would remove them from the array. However I am struggling to do this with ARC because it doesn't let me monitor retain/release, how would I go about doing this?
Creating a way to manage objects based on release/retains calls, it's dangerous. If Apple happens to change the way it works, you are screwed. And apparently, that's what happened, when you start using ARC. There are two things:
1) You want to keep the objects inside the NSMutableArray independently if they are being use by other objects or not. In that case, just create a __weak reference to that objects, and in that way your object, that is inside the NSMutableArray, is kept alive.
2) Once there are not references to the object, just remove it from the NSMutableArray. Add to the NSMutableArray a __weak object. Once the strong one is release, the one inside the array will be as well, although I don't really like this approach as I find it dangerous. If you go for this option, use this to store the objects:
NSValue *weakObject = [NSValue valueWithNonretainedObject:anObject];
[array addObject:weakObject];
In the end, you can simply remove ARC from that specific file, and you can keep the monitoring.
I wouldn't bother with such a complex system. Just work with strong and weak properties and don't try to second guess performance. You are trying to build a memory management system yourself which makes little sense with ARC around. Creating and deleting objects is generally a tiny percentage of performance of any objective-c app; after years of using Instruments to monitor performance I don't worry about this part any more.
First, you should write simple code, intended for humans.
Do not worry about such performance issues until you have proven (via instruments or some other measure) that this is a critical bottleneck.
That said, creating certain objects can be really expensive, so keeping a cache for certain objects is not in and of itself a bad idea. However, you should never rely on reference counts, even in non-ARC code. Apple docs are very clear about this.
The alternative, as Jacky pointed out is a weak reference. Unfortunately, you can not put a weak reference into standard collections (though, ironically, you can put them in C++ collections and they will be managed correctly).
However, you can create a simple wrapper class to hold a weak reference.
#interface WeakWrapper : NSObject
#property (readonly) id object;
- (id)initWithObject:(id)object;
#end
#implementation WeakWrapper {
__weak id _object;
}
- (id)object {
return _object;
}
- (id)initWithObject:(id)object {
if (self = [super init]) {
_object = object;
}
return self;
}
#end
You can then place these objects inside collections, and then...
WeakWrapper *wrapper = // get the object from the collection
id object = wrapper.object;
if (nil == object) {
// You know the object that was being referenced no longer exists
// so this wrapper can be removed from the collection and destroyed.
}
I've seen some answers but those didn't expand enough and I think they were before ARC was introduced.
So if I have two NSSstring can I set
string1 =string2;
or
NSString * a1=#"String";
al=#"Lead";
without causing memory leaks or other problems?
Edit: What about view controller or delegate properties set to (copy, nonatomic)?
Edit2: It should be NSString *al=#"String". I hope this doesn't change the idea that it doesn't leak.
No, assigning and re-assigning string literals will not cause a memory leak. You only need to worry about memory leaks when not using ARC and assigning something that uses alloc, retain, copy, mutableCopy or a method prefixed with new.
NSString a1=[#"String" mutableCopy];
al=#"Lead";//This will cause a leak since you called copy above.
See the Advance Memory Management Rules for details.
neither would leak in ARC.
however, you might want to be aware that you are dealing with a reference in this case -- no implicit copy is performed (unless you use a copy or copy-qualified property).
Edit: What about view controller or delegate properties set to (copy, nonatomic)?
for NSStrings? yes, copy should be the default for NSStrings. nonatomic should be the default for everything. of course, there are exceptions to this -- when you might deviate from the defaults.
Your code is safe and will not leak. Cocoa and NSStrings are quite smart about how they deal with these issues.
You can end up with other interesting things happening because NSStrings are immutable, and you can get weirdness if you try to worry about the pointers themselves. But your examples don't suffer from these issues.
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.