1

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.

brain56
  • 2,659
  • 9
  • 38
  • 70

4 Answers4

3

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.

Abizern
  • 146,289
  • 39
  • 203
  • 257
2

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.

Alex
  • 1,581
  • 1
  • 11
  • 27
  • 1
    ARC code definitely can have real leaks — for example, in the case of cyclical references or places where you use CFRetain. – Chuck May 08 '13 at 19:03
0

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
    }
}
Community
  • 1
  • 1
Daij-Djan
  • 49,552
  • 17
  • 113
  • 135
  • 1
    why is that wrong? arc may autorelease o and a pool will make it dealloc it. anyways even it is I'd ALWAYS love a comment from the down voter! – Daij-Djan May 08 '13 at 07:55
  • e.g. if you do `for(i = 0; i< 1000;i++) o = [MyObj new];` that would alloc 1000s of os and a pool might make sense (yes, in THIS case in the loop maybe) – Daij-Djan May 08 '13 at 07:57
  • 1
    Unless you're creating lots of temporary objects in a loop it won't make any difference. And even then - it just releases the memory faster, it doesn't guarantee any extra level of memory management. – Abizern May 08 '13 at 08:02
  • `[MyObj new]` is a bad example, because that returns a (+1) retained object. But methods that do not start with alloc/copy/init/mutableCopy/new *can* return autoreleased objects, therefore a local autorelease pool can be useful to reduce the memory footprint. - It would not help to avoid a *leak*, which was the OP's concern. – Martin R May 08 '13 at 08:03
  • This sounds like voodoo. A local autorelease pool will not have any effect on objects that are not autoreleased within its scope. – Chuck May 08 '13 at 08:10
  • Thanks Martin I thought/think that even one of the methods that traditionally aren't autoreleased and would be released could be made autoreleased by ARC... that's how I read the docs – Daij-Djan May 08 '13 at 08:13
  • "The compiler efficiently eliminates many extraneous retain/release calls and much effort has been invested in speeding up the Objective-C runtime in general." – Daij-Djan May 08 '13 at 08:14
  • 1
    @Daij-Djan: It is the other way around: the compiler can *avoid* an autorelease (see e.g. this comment: http://stackoverflow.com/questions/16379288/why-is-objective-c-arc-deallocation-dependent-on-whether-an-object-was-created-i/16379474#comment23475242_16379474). – Martin R May 08 '13 at 08:23
  • thanks :) Ill not delete this discussion but Ill edit my answer – Daij-Djan May 08 '13 at 08:57
  • Reversed my downvote. I think the discussion will be helpful to passersby. – Abizern May 08 '13 at 12:57
0

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.

7ynk3r
  • 958
  • 13
  • 17