205

For the most part with ARC (Automatic Reference Counting), we don't need to think about memory management at all with Objective-C objects. It is not permitted to create NSAutoreleasePools anymore, however there is a new syntax:

@autoreleasepool {
    …
}

My question is, why would I ever need this when I'm not supposed to be manually releasing/autoreleasing ?


EDIT: To sum up what I got out of all the anwers and comments succinctly:

New Syntax:

@autoreleasepool { … } is new syntax for

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
…
[pool drain];

More importantly:

  • ARC uses autorelease as well as release.
  • It needs an auto release pool in place to do so.
  • ARC doesn't create the auto release pool for you. However:
    • The main thread of every Cocoa app already has an autorelease pool in it.
  • There are two occasions when you might want to make use of @autoreleasepool:
    1. When you are in a secondary thread and there is no auto release pool, you must make your own to prevent leaks, such as myRunLoop(…) { @autoreleasepool { … } return success; }.
    2. When you wish to create a more local pool, as @mattjgalloway has shown in his answer.
Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
mk12
  • 25,873
  • 32
  • 98
  • 137
  • 1
    There is also a third occasion: When you develop something that is not related to UIKit or NSFoundation. Something that uses command line tools or so – Garnik Aug 05 '18 at 18:08

8 Answers8

231

ARC doesn't get rid of retains, releases and autoreleases, it just adds in the required ones for you. So there are still calls to retain, there are still calls to release, there are still calls to autorelease and there are still auto release pools.

One of the other changes they made with the new Clang 3.0 compiler and ARC is that they replaced NSAutoReleasePool with the @autoreleasepool compiler directive. NSAutoReleasePool was always a bit of a special "object" anyway and they made it so that the syntax of using one is not confused with an object so that it's generally a bit more simple.

So basically, you need @autoreleasepool because there are still auto release pools to worry about. You just don't need to worry about adding in autorelease calls.

An example of using an auto release pool:

- (void)useALoadOfNumbers {
    for (int j = 0; j < 10000; ++j) {
        @autoreleasepool {
            for (int i = 0; i < 10000; ++i) {
                NSNumber *number = [NSNumber numberWithInt:(i+j)];
                NSLog(@"number = %p", number);
            }
        }
    }
}

A hugely contrived example, sure, but if you didn't have the @autoreleasepool inside the outer for-loop then you'd be releasing 100000000 objects later on rather than 10000 each time round the outer for-loop.

Update: Also see this answer - https://stackoverflow.com/a/7950636/1068248 - for why @autoreleasepool is nothing to do with ARC.

Update: I took a look into the internals of what's going on here and wrote it up on my blog. If you take a look there then you will see exactly what ARC is doing and how the new style @autoreleasepool and how it introduces a scope is used by the compiler to infer information about what retains, releases & autoreleases are required.

Community
  • 1
  • 1
mattjgalloway
  • 34,792
  • 12
  • 100
  • 110
  • `ARC doesn't get rid of retains…` But your code doesn't compile under ARC if you have a single call to any of these, so what is it that you mean? – mk12 Jan 31 '12 at 21:14
  • 14
    It doesn't get rid of retains. It adds them in for you. Reference counting is still going in, it's just automatic. Hence Automatic Reference Counting :-D. – mattjgalloway Jan 31 '12 at 21:16
  • 7
    So why doesn't it add in the `@autoreleasepool` for me too? If I'm not controlling what gets autoreleased or released (ARC does that for me), how should I know when to set up an autorelease pool? – mk12 Jan 31 '12 at 21:18
  • 6
    But you have control over where your auto release pools go still. There's one wrapped around your whole app by default, but you might want more. – mattjgalloway Jan 31 '12 at 21:27
  • 6
    Good question. You just have to "know". Think of adding one as akin to why one might, in a GC language, add a hint to a garbage collector to go ahead and run a collect cycle now. Maybe you know there's a ton of objects ready to be cleared out, you have a loop that allocates a bunch of temp objects, so you "know" (or Instruments might tell you :) that adding a release pool around the loop would be a good idea. – Graham Perks Jan 31 '12 at 21:28
  • @GrahamPerks: Okay that definately clears a lot up. One final question: will there ever be a case where *not* setting up an `@autoreleasepool` block will result in crash? I would think not since you are likening it to a hint, but consider the situtation I explained in the comment below on DougW's answer. – mk12 Jan 31 '12 at 21:33
  • @Mk12 - you'll always still have your outer auto release pool which will get drained. And anyway, it would never result in a crash not having one. The only thing that would happen if you didn't have one is leak objects. That's only going to cause a crash if you run out of memory. – mattjgalloway Jan 31 '12 at 21:35
  • 7
    The looping example works perfectly fine without autorelease: each object is deallocated when the variable goes out of scope. Running the code without autorelease takes a constant amount of memory and shows pointers being reused, and putting a breakpoint on an object's dealloc shows it being called once each time through the loop, when objc_storeStrong is called. Maybe OSX does something dumb here, but autoreleasepool is completely unnecessary on iOS. – Glenn Maynard Feb 24 '14 at 21:56
  • @GlennMaynard Yes, but only because of an optimisation that ARC makes where if the caller and callee are both using ARC, then the autorelease in the return from `numberWithInt:` and subsequent retain in the caller are cancelled out. Then when the caller releases the `NSNumber`, it is the final one to hold onto it and is deallocated. But saying autorelease pools are completely unnecessary on iOS is entirely incorrect. They are still very much alive and absolutely necessary. – mattjgalloway Feb 25 '14 at 09:42
  • @GlennMaynard To put it another way - this example is contrived and sadly doesn't quite show the use of autorelease pools any more, given the new optimisation that I refer to. But imagine a world without this optimisation and the example makes full sense. – mattjgalloway Feb 25 '14 at 09:43
  • Does this mean that if I use ARC and release an object from somewhere outside the ``@autoreleasepool{}`` the object still exists until the end of the @autoreleasepool block? – Michael Feb 23 '15 at 00:17
  • Correct me if I am wrong, I thought ARC will insert release instead of autorelease in this case (I thought autorelease only inserted when object is used for return), so in your example, having an autorelease pool or not does not seems to matter. – Helin Wang Sep 10 '15 at 20:07
  • Now I get it, [NSNumber numberWithInt] returns an autoreleased object. I think it's good to point it out for beginners like me. – Helin Wang Sep 10 '15 at 20:10
  • 1
    Sorry for more comments, can not edit the previous ones --- Hmm, but doesn't assigning return result to variable number automatically cause ARC to retain it, so ARC will release it after the current loop completes. So I still do not get why autorelease pool is necessary. – Helin Wang Sep 10 '15 at 20:17
  • I think the example could be updated, but correct me if im wrong the autorelease pool will be useful if making lots of objects marked with `__autoreleasing` [(see this)](http://stackoverflow.com/a/8862061/1219956), or does that compiler optimisation mentioned by @GlennMaynard still apply in this case as well? – Fonix Apr 26 '16 at 07:04
  • Yes, this example needs to be updated, possibly even more contrived to show how it really makes a difference for iOS in particular – Bradley Thomas Oct 06 '16 at 19:33
18

@autoreleasepool doesn't autorelease anything. It creates an autorelease pool, so that when the end of block is reached, any objects that were autoreleased by ARC while the block was active will be sent release messages. Apple's Advanced Memory Management Programming Guide explains it thus:

At the end of the autorelease pool block, objects that received an autorelease message within the block are sent a release message—an object receives a release message for each time it was sent an autorelease message within the block.

outis
  • 75,655
  • 22
  • 151
  • 221
  • 1
    Not necessarily. The object will receive a `release` message but if the retain count is > 1 the object will NOT be deallocated. – andybons Apr 17 '13 at 02:55
  • @andybons: updated; thanks. Is this a change from pre-ARC behavior? – outis Apr 19 '13 at 20:48
  • This is incorrect. Objects released by ARC will be sent release messages as soon as they're released by ARC, with or without an autorelease pool. – Glenn Maynard Feb 24 '14 at 22:01
9

People often misunderstand ARC for some kind of garbage collection or the like. The truth is that, after some time people at Apple (thanks to llvm and clang projects) realized that Objective-C's memory administration (all the retains and releases, etc.) can be fully automatized at compile time. This is, just by reading the code, even before it is run! :)

In order to do so there is only one condition: We MUST follow the rules, otherwise the compiler would not be able to automate the process at compile time. So, to ensure that we never break the rules, we are not allowed to explicitly write release, retain, etc. Those calls are Automatically injected into our code by the compiler. Hence internally we still have autoreleases, retain, release, etc. It is just we don't need to write them anymore.

The A of ARC is automatic at compile time, which is much better than at run time like garbage collection.

We still have @autoreleasepool{...} because having it does not break any of the rules, we are free create/drain our pool anytime we need it :).

Todd Lehman
  • 2,880
  • 1
  • 26
  • 32
nacho4d
  • 43,720
  • 45
  • 157
  • 240
  • 1
    ARC is reference counting GC, not mark-and-sweep GC like you get in JavaScript and Java, but it's definitely garbage collection. This doesn't address the question--"you can" doesn't answer the question of "why should you". You shouldn't. – Glenn Maynard Feb 24 '14 at 21:58
6

Autorelease pools are required for returning newly created objects from a method. E.g. consider this piece of code:

- (NSString *)messageOfTheDay {
    return [[NSString alloc] initWithFormat:@"Hello %@!", self.username];
}

The string created in the method will have a retain count of one. Now who shall balance that retain count with a release?

The method itself? Not possible, it has to return the created object, so it must not release it prior to returning.

The caller of the method? The caller does not expect to retrieve an object that needs releasing, the method name does not imply that a new object is created, it only says that an object is returned and this returned object may be a new one requiring a release but it may as well be an existing one that doesn't. What the method does return may even depend on some internal state, so the the caller cannot know if it has to release that object and it shouldn't have to care.

If the caller had to always release all returned object by convention, then every object not newly created would always have to be retained prior to returning it from a method and it would have to be released by the caller once it goes out of scope, unless it is returned again. This would be highly inefficient in many cases as one can completely avoid altering retain counts in many cases if the caller will not always release the returned object.

That's why there are autorelease pools, so the first method will in fact become

- (NSString *)messageOfTheDay {
    NSString * res = [[NSString alloc] initWithFormat:@"Hello %@!", self.username];
    return [res autorelease];
}

Calling autorelease on an object adds it to the autorelease pool, but what does that really mean, adding an object to the autorelease pool? Well, it means telling your system "I want you to to release that object for me but at some later time, not now; it has a retain count that needs to be balanced by a release otherwise memory will leak but I cannot do that myself right now, as I need the object to stay alive beyond my current scope and my caller won't do it for me either, it has no knowledge that this needs to be done. So add it to your pool and once you clean up that pool, also clean up my object for me."

With ARC the compiler decides for you when to retain an object, when to release an object and when to add it to an autorelease pool but it still requires the presence of autorelease pools to be able to return newly created objects from methods without leaking memory. Apple has just made some nifty optimizations to the generated code which will sometimes eliminate autorelease pools during runtime. These optimizations require that both, the caller and the callee are using ARC (remember mixing ARC and non-ARC is legal and also officially supported) and if that is actually the case can only be known at runtime.

Consider this ARC Code:

// Callee
- (SomeObject *)getSomeObject {
    return [[SomeObject alloc] init];
}

// Caller
SomeObject * obj = [self getSomeObject];
[obj doStuff];

The code that the system generates, can either behave like the following code (that is the safe version that allows you to freely mix ARC and non-ARC code):

// Callee
- (SomeObject *)getSomeObject {
    return [[[SomeObject alloc] init] autorelease];
}

// Caller
SomeObject * obj = [[self getSomeObject] retain];
[obj doStuff];
[obj release];

(Note the retain/release in the caller is just a defensive safety retain, it's not strictly required, the code would be perfectly correct without it)

Or it can behave like this code, in case that both are detected to use ARC at runtime:

// Callee
- (SomeObject *)getSomeObject {
    return [[SomeObject alloc] init];
}

// Caller
SomeObject * obj = [self getSomeObject];
[obj doStuff];
[obj release];

As you can see, Apple eliminates the atuorelease, thus also the delayed object release when the pool is destroyed, as well as the safety retain. To learn more about how that is possible and what's really going on behind the scenes, check out this blog post.

Now to the actual question: Why would one use @autoreleasepool?

For most developers, there's only one reason left today for using this construct in their code and that is to keep the memory footprint small where applicable. E.g. consider this loop:

for (int i = 0; i < 1000000; i++) {
    // ... code ...
    TempObject * to = [TempObject tempObjectForData:...];
    // ... do something with to ...
}

Assume that every call to tempObjectForData may create a new TempObject that is returned autorelease. The for-loop will create one million of these temp objects which are all collected in the current autoreleasepool and only once that pool is destroyed, all the temp objects are destroyed as well. Until that happens, you have one million of these temp objects in memory.

If you write the code like this instead:

for (int i = 0; i < 1000000; i++) @autoreleasepool {
    // ... code ...
    TempObject * to = [TempObject tempObjectForData:...];
    // ... do something with to ...
}

Then a new pool is created every time the for-loop runs and is destroyed at the end of each loop iteration. That way at most one temp object is hanging around in memory at any time despite the loop running one million times.

In the past you often had to also manage autoreleasepools yourself when managing threads (e.g. using NSThread) as only the main thread automatically has an autorelease pool for a Cocoa/UIKit app. Yet this is pretty much legacy today as today you probably wouldn't use threads to begin with. You'd use GCD DispatchQueue's or NSOperationQueue's and these two both do manage a top level autorelease pool for you, created before running a block/task and destroyed once done with it.

Mecki
  • 125,244
  • 33
  • 244
  • 253
3

Quoted from https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html:

Autorelease Pool Blocks and Threads

Each thread in a Cocoa application maintains its own stack of autorelease pool blocks. If you are writing a Foundation-only program or if you detach a thread, you need to create your own autorelease pool block.

If your application or thread is long-lived and potentially generates a lot of autoreleased objects, you should use autorelease pool blocks (like AppKit and UIKit do on the main thread); otherwise, autoreleased objects accumulate and your memory footprint grows. If your detached thread does not make Cocoa calls, you do not need to use an autorelease pool block.

Note: If you create secondary threads using the POSIX thread APIs instead of NSThread, you cannot use Cocoa unless Cocoa is in multithreading mode. Cocoa enters multithreading mode only after detaching its first NSThread object. To use Cocoa on secondary POSIX threads, your application must first detach at least one NSThread object, which can immediately exit. You can test whether Cocoa is in multithreading mode with the NSThread class method isMultiThreaded.

...

In Automatic Reference Counting, or ARC, the system uses the same reference counting system as MRR, but it insertsthe appropriate memory management method callsfor you at compile-time. You are strongly encouraged to use ARC for new projects. If you use ARC, there is typically no need to understand the underlying implementation described in this document, although it may in some situations be helpful. For more about ARC, see Transitioning to ARC Release Notes.

Raunak
  • 3,314
  • 1
  • 22
  • 28
3

It's because you still need to provide the compiler with hints about when it is safe for autoreleased objects to go out of scope.

DougW
  • 28,776
  • 18
  • 79
  • 107
  • Can you give me an example of when you would need to do this? – mk12 Jan 31 '12 at 21:10
  • [Using Autorelease Pools](http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html#//apple_ref/doc/uid/20000047-CJBFBEDI) – rob mayoff Jan 31 '12 at 21:18
  • So before ARC, for example, I had a CVDisplayLink running on a secondary thread for my OpenGL app, but I didn't create an autorelease pool in its runloop because I knew I wasn't autorealeasing anything (or using libraries that do). Does that mean now I do need to add `@autoreleasepool` because I don't know if ARC might decide to autorelease something? – mk12 Jan 31 '12 at 21:24
  • @Mk12 - No. You will always still have an auto release pool that gets drained each time round the main run loop. You should only need to add one when you want to ensure that objects that have been autoreleased get drained before they would otherwise - for example, the next time round the run loop. – mattjgalloway Jan 31 '12 at 21:33
  • @DougW - It's not a hint for when it's safe for autoreleased objects to go out of scope at all. It's also not the compiler that's concerned, it's all at runtime this. – mattjgalloway Jan 31 '12 at 21:34
  • Its on a secondary thread though, which doesn't have the main run loop's autorelease pool. I based my code on the apple sample code, which included the following in the beginning of the run loop method: `// We're on a secondary thread, so create an NSAutorelease pool // or else objects will be leaked. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];` – mk12 Jan 31 '12 at 21:37
  • @Mk12 - Oh sorry then, yes, you'd want an auto release pool. But if you use GCD then things will just magically work (as it creates an auto release pool for you). Sorry I missed the bit about secondary thread :-/. – mattjgalloway Jan 31 '12 at 21:40
  • @mattjgalloway - Okay yes, to be accurate it is more than a "hint". But `@autoreleasepool` is not a runtime instruction. It is a pre-compiler directive. From Apple's docs: "This simple structure allows the compiler to reason about the reference count state.". – DougW Jan 31 '12 at 23:00
  • @DougW - It's true that the compiler will reason about the reference count state when using ARC - but there will still be auto releases going on at runtime and pools will be drained. It's now simpler (introduces a scope) for the compiler to understand if it actually needs to do an autorelease, i.e. it might be able to cancel out one autorelease with one retain. `@autoreleasepool` is not a runtime instruction, but there are still auto release pools that are drained at runtime. – mattjgalloway Feb 01 '12 at 10:12
  • 2
    @DougW - I took a look into what the compiler is actually doing and blogged about it here - http://iphone.galloway.me.uk/2012/02/a-look-under-arcs-hood-–-episode-3/ . Hopefully explains what's going on at both compile-time and run-time. – mattjgalloway Feb 01 '12 at 10:56
  • @mattjgalloway - Great write up. I think we're all in agreement here, and I'm sure some folks are interested in reading a more detailed explanation than I gave, so thanks for providing it. – DougW Feb 01 '12 at 19:11
2

TL;DR

Why is @autoreleasepool still needed with ARC?

@autoreleasepool is used by Objective-C and Swift to work with autorelese inside

When you work with pure Swift and allocate Swift objects - ARC handles it

But if you decide call/use Foundation/Legacy Objective-C code(NSData, Data) which uses autorelese inside then @autoreleasepool in a rescue

//Swift
let imageData = try! Data(contentsOf: url)

//Data init uses Objective-C code with [NSData dataWithContentsOfURL] which uses `autorelese`

Long answer

MRC, ARC, GC

Manual Reference Counting(MRC) or Manual Retain-Release(MRR) as a developer you are responsible for counting references on objects manually

Automatic Reference Counting(ARC) was introduced in iOS v5.0 and OS X Mountain Lion with xCode v4.2

Garbage Collection(GC) was available for Mac OS and was deprecated in OS X Mountain Lion. Must Move to ARC

Reference count in MRC and ARC

//MRC
NSLog(@"Retain Count: %d", [variable retainCount]);

//ARC
NSLog(@"Retain Count: %ld", CFGetRetainCount((__bridge CFTypeRef) variable));

Every object in heap has an integer value which indicates how many references are pointed out on it. When it equals to 0 object is deallocated by system

  • Allocating object
  • Working with Reference count
  • Deallocating object. deinit is called when retainCount == 0

MRC

A *a1 = [[A alloc] init]; //this A object retainCount = 1
    
A *a2 = a1;
[a2 retain]; //this A object retainCount = 2

// a1, a2 -> object in heap with retainCount

Correct way to release an object:

  1. release If only this - dangling pointer. Because it still can point on the object in heap and it is possible to send a message
  2. = nil If only this - memory leak. deinit will not be called
A *a = [[A alloc] init]; //++retainCount = 1
[a release]; //--retainCount = 0
a = nil; //guarantees that even somebody else has a reference to the object, and we try to send some message thought variable `a` this message will be just skipped

Working with Reference count(Object owner rules):

  • (0 -> 1) alloc, new, copy, mutableCopy
  • (+1) retain You are able to own an object as many times as you need(you can call retain several times)
  • (-1) release If you an owner you must release it. If you release more than retainCount it will be 0
  • (-1) autorelease Adds an object, which should be released, to autorelease pool. This pool will be processed at the end of RunLoop iteration cycle(it means when all tasks will be finished on the stack)[About] and after that release will be applied for all objects in the pool
  • (-1) @autoreleasepool Forces process an autorelease pool at the end of block. It is used when you deal with autorelease in a loop and want to clear resources ASAP. If you don't do it your memory footprint will be constantly increasing

autorelease is used in method calls when you allocate a new object there and return it

- (B *)foo {
    B *b1 = [[B alloc] init]; //retainCount = 1

    //fix - correct way - add it to fix wrong way
    //[b1 autorelease];

    //wrong way(without fix)
    return b; 
}

- (void)testFoo {
    B *b2 = [a foo];
    [b2 retain]; //retainCount = 2
    //some logic
    [b2 release]; //retainCount = 1
    
    //Memory Leak
}

@autoreleasepool example

- (void)testFoo {
    for(i=0; i<100; i++) {
        B *b2 = [a foo];
        //process b2
    }
}

ARC

One of biggest advantage of ARC is that it automatically insert retain, release, autorelease under the hood in Compile Time and as developer you should not take care of it anymore

Enable/Disable ARC

//enable
-fobjc-arc
//disable
-fno-objc-arc

Variants from more to less priority

//1. local file - most priority
Build Phases -> Compile Sources -> Compiler Flags(Select files -> Enter) 

//2. global
Build Settings -> Other C Flags(OTHER_CFLAGS)

//3. global
Build Settings -> Objective-C Automatic Reference Counting(CLANG_ENABLE_OBJC_ARC)

Check if ARC is enabled/disabled

Preprocessor __has_feature function is used

__has_feature(objc_arc)

Compile time

// error if ARC is Off. Force to enable ARC
#if  ! __has_feature(objc_arc)
    #error Please enable ARC for this file
#endif

//or

// error if ARC is On. Force to disable ARC
#if  __has_feature(objc_arc)
    #error Please disable ARC for this file
#endif

Runtime

#if __has_feature(objc_arc)
    // ARC is On
    NSLog(@"ARC on");
#else
    // ARC is Off
    NSLog(@"ARC off");
#endif

Reverse engineering(for Objective-C)

//ARC is enabled
otool -I -v <binary_path> | grep "<mrc_message>"
//e.g.
otool -I -v "/Users/alex/ARC_experiments.app/ARC_experiments"  | grep "_objc_release"

//result
0x00000001000080e0   748 _objc_release

//<mrc_message>
_objc_retain
_objc_release
_objc_autoreleaseReturnValue
_objc_retainAutoreleaseReturnValue
_objc_retainAutoreleasedReturnValue
_objc_storeStrong

Tool to Migrate Objective-C MRC to ARC

ARC generates errors where you should manually remove retain, release, autorelease and others issues

Edit -> Convert -> To Objective-C ARC...

New Xcode with MRC

If you enable MRC you get next errors(warnings)(but the build will be successful)

//release/retain/autorelease/retainCount
'release' is unavailable: not available in automatic reference counting mode
ARC forbids explicit message send of 'release'
yoAlex5
  • 29,217
  • 8
  • 193
  • 205
-4

There seems to be a lot of confusion on this topic (and at least 80 people who probably are now confused about this and think they need to sprinkle @autoreleasepool around their code).

If a project (including its dependencies) exclusively uses ARC, then @autoreleasepool never needs to be used and will do nothing useful. ARC will handle releasing objects at the correct time. For example:

@interface Testing: NSObject
+ (void) test;
@end

@implementation Testing
- (void) dealloc { NSLog(@"dealloc"); }

+ (void) test
{
    while(true) NSLog(@"p = %p", [Testing new]);
}
@end

displays:

p = 0x17696f80
dealloc
p = 0x17570a90
dealloc

Each Testing object is deallocated as soon as the value goes out of scope, without waiting for an autorelease pool to be exited. (The same thing happens with the NSNumber example; this just lets us observe the dealloc.) ARC does not use autorelease.

The reason @autoreleasepool is still allowed is for mixed ARC and non-ARC projects, which haven't yet completely transitioned to ARC.

If you call into non-ARC code, it may return an autoreleased object. In that case, the above loop would leak, since the current autorelease pool will never be exited. That's where you'd want to put an @autoreleasepool around the code block.

But if you've completely made the ARC transition, then forget about autoreleasepool.

Glenn Maynard
  • 55,829
  • 10
  • 121
  • 131
  • 4
    This answer is wrong and also goes against ARC documentation. your evidence is anecdotal because you happen to be using an allocation method that the compiler decides not to autorelease. You can very easily see this not working if you create a new static initializer for your custom class. Create this initializer and use it in your loop: `+ (Testing *) testing { return [Testing new] }`. Then you'll see that dealloc won't get called until later on. This is fixed if you wrap the inside of the loop in an `@autoreleasepool` block. – Dima Jul 14 '14 at 01:30
  • @Dima Tried on iOS10, dealloc get called immediately after printing the object address. `+ (Testing *) testing { return [Testing new];} + (void) test { while(true) NSLog(@"p = %p", [self testing]);}` – KudoCC Oct 26 '16 at 04:31
  • @KudoCC - So did I, and I saw the same behavior that you did. But, when I threw `[UIImage imageWithData]` into the equation, then, all of a sudden, I started seeing the traditional `autorelease` behavior, requiring `@autoreleasepool` to keep peak memory to some reasonable level. – Rob Oct 26 '16 at 18:19
  • @Rob I can't help myself add the [link](http://stackoverflow.com/questions/19840676/autorelease-pools-and-when-release-is-called-under-ios/19842107#19842107). – KudoCC Oct 27 '16 at 02:48