Advertise Mobile SDKs Books Events Forum News Social Networking Support Us
Follow @iphonedevsdk on Twitter

Interface 2, Advanced iOS
Mockup & Code Gen
($9.99)

Make your own iPhone apps
and run them live!
(free)

Pic Frame Dynamo: Photo Editing
($0.99)

Abiliator
($1.99)

Want your application or service advertised on iPhone Dev SDK?

Go Back   iPhone Dev SDK Forum > Mac OS X Development Forums > Objective-C, Python, Ruby Development

Reply
 
LinkBack Thread Tools Display Modes
Old 05-09-2009, 05:29 AM   #1 (permalink)
Registered Member
 
Join Date: Apr 2009
Posts: 13
hcarsten is on a distinguished road
Default How to get rid of autorelease

Hi All,
as a not very experienced objective-c developer (on iphone) I have a general problem with "autorelease" variables.

Is there anyway to get rid of a variable that already had already received a "autorelease" message?

As a simple scenario I have a regularly fired piece of code that just formats the current time as a string and shows it in UILabel. Using NSDate/NSDateFormater would create a couple of "autorelease" vars.

My understanding here is that these vars would never be released till the assigned autorelease-pool is releases. So normally when the application finishes. I would assume then that the pool managed memory is increasing as more as longer the app is running.

I know that recreating a new autorelease-pool might solve the issue. But is this really the desired way to do it; so re-creating an autorelease pool in a method to get rid of all the autorelease objects within the method? I would assume that re-creating a pool is a rather expensive operation.

Maybe I did not already understood the way NSAutoreleasePool is working, but I assume drain/release is only called once during the live-time of the pool. Or is there any additional "magic" (e.g. the drain method is automatically called in the application-event loop) ?

Finally, is the following code-snipple a developer might is opposed to do to reduce the memory preasure :

Code:
// calling a method that returns an "autorelease" object
NSString* aString = [SomeClass stringWithData:@"xyz"];

// ... once being ready with the aString
[globalPool drain];
appreciate any help on this. Please no references to generals hint aka "read the manual" I already did this, but could not find anything yet ...

best wishes

Carsten
hcarsten is offline   Reply With Quote
Old 05-09-2009, 07:12 AM   #2 (permalink)
Former NeXTStep Developer
 
Join Date: Mar 2009
Posts: 997
FlyingDiver will become famous soon enough
Default

Quote:
My understanding here is that these vars would never be released till the assigned autorelease-pool is releases. So normally when the application finishes. I would assume then that the pool managed memory is increasing as more as longer the app is running.
The default auto-release pool is drained every time through the run loop, not once per application lifecycle. So as soon as your current stack of method calls completes, and you're back waiting for a UI event, the pool is drained.

If you have some specific piece of code in one of you object methods that creates a LOT of auto-released objects, then it might be worth setting up an auto-release pool in that method, so it can be drained immediately. Otherwise, this really shouldn't be a problem.

joe
FlyingDiver is offline   Reply With Quote
Old 05-09-2009, 10:45 AM   #3 (permalink)
Pro. Game Developer
iPhone Dev SDK Supporter
 
Join Date: Feb 2009
Location: żLa Islas Hermosas?
Posts: 2,176
Kalimba is on a distinguished road
Default

Quote:
Originally Posted by hcarsten View Post
Is there anyway to get rid of a variable that already had already received a "autorelease" message?
Well... technically, if you have a variable that has been sent 'autorelease', yet still has a retain count of 1, you can send it a 'release' and it will be released right then and there. BUT YOU DON'T EVER WANT TO DO THIS, because your app will crash when the autorelease pool is released.

Quote:
Originally Posted by hcarsten View Post
As a simple scenario I have a regularly fired piece of code that just formats the current time as a string and shows it in UILabel. Using NSDate/NSDateFormater would create a couple of "autorelease" vars.

My understanding here is that these vars would never be released till the assigned autorelease-pool is releases. So normally when the application finishes. I would assume then that the pool managed memory is increasing as more as longer the app is running.
As Joe pointed out, your understanding about when variables in the autorelease pool are released is slightly incorrect. Most applications create an autorelease pool in their 'main' function, but that pool is simply the first in a stack of pools that exist during execution of your application. The operating system creates autorelease pools before dispatching events to your application, and those pools are drained when your code returns control the the OS. So any autorelease variable you create in a single "message cycle" are cleaned up some time before the next cycle.

Quote:
Originally Posted by hcarsten View Post
I know that recreating a new autorelease-pool might solve the issue. But is this really the desired way to do it; so re-creating an autorelease pool in a method to get rid of all the autorelease objects within the method? I would assume that re-creating a pool is a rather expensive operation.
If you have code that generates a significant number of autoreleased objects, then creating your own autorelease pool is a good solution. BTW, you're not "recreating" an existing autorelease pool, just pushing your pool onto the stack of pools such that it becomes the container for objects to be autoreleased. As soon as you 'drain' your pool, it sends 'release' to all objects in the pool and removes itself from the pool stack. AFAIK, there is no noticeable overhead in creating your own autorelease pool.

Quote:
Originally Posted by hcarsten View Post
Maybe I did not already understood the way NSAutoreleasePool is working, but I assume drain/release is only called once during the live-time of the pool. Or is there any additional "magic" (e.g. the drain method is automatically called in the application-event loop) ?
That's correct. Once a pool is 'drained', it is removed from the pool stack and released itself.

Quote:
Originally Posted by hcarsten View Post
Finally, is the following code-snipple a developer might is opposed to do to reduce the memory preasure :

Code:
// calling a method that returns an "autorelease" object
NSString* aString = [SomeClass stringWithData:@"xyz"];

// ... once being ready with the aString
[globalPool drain];
No, you don't ever want to do that, but if you've read all of my earlier responses, you probably know that by now. Any autorelease pool should only be drained once, and from the same context in which it was created.

Hope all of this helps more that it confuses.
__________________
~~ Word Flurry ~~ App Store / Website / Facebook
Kalimba is offline   Reply With Quote
Old 05-10-2009, 05:45 AM   #4 (permalink)
Registered Member
 
Join Date: Apr 2009
Posts: 13
hcarsten is on a distinguished road
Default

thanks for this deep explanation.
It really makes sense to have the application loop draining the pool in every idle state; in fact I was hoping something like this.

best wishes

Carsten
hcarsten is offline   Reply With Quote
Old 05-29-2009, 11:42 AM   #5 (permalink)
Registered Member
 
tawpie's Avatar
 
Join Date: Jul 2008
Posts: 347
tawpie is an unknown quantity at this point
Default

I am wondering though, if there is a way to safely "force" the draining of main's autorelease pool without returning to the main run loop? I'd like to send the drain message from my mainViewController object...

What I have going is during regression testing I hang in a very tight loop exercising basically all of my methods with randomly varied entry conditions -- which means that I essentially never get back to the main run loop AND my autorelease pool doesn't drain. The issue arises because instance variables created with convenience methods don't drain either and gradually accumulate as crud and eventually it goes boom.

It's not a show stopper as it's a regression test thing only, but I'd really like to let it run for days on end while the confuser isn't doing anything else important.
__________________
"Hardware will break. Software comes broken" Unknown
Calc-12E <-- ditch your old calculator.
CPR•Choking <-- Review your training, just in case. (Free)
All of Nature NW <-- scrolls in x and y, with pinch zoom AND scrollable text to boot. It can be done ('taint easy tho)
tawpie is offline   Reply With Quote
Old 05-29-2009, 12:04 PM   #6 (permalink)
Pro. Game Developer
iPhone Dev SDK Supporter
 
Join Date: Feb 2009
Location: żLa Islas Hermosas?
Posts: 2,176
Kalimba is on a distinguished road
Default

Quote:
Originally Posted by tawpie View Post
I am wondering though, if there is a way to safely "force" the draining of main's autorelease pool without returning to the main run loop? I'd like to send the drain message from my mainViewController object...

What I have going is during regression testing I hang in a very tight loop exercising basically all of my methods with randomly varied entry conditions -- which means that I essentially never get back to the main run loop AND my autorelease pool doesn't drain. The issue arises because instance variables created with convenience methods don't drain either and gradually accumulate as crud and eventually it goes boom.

It's not a show stopper as it's a regression test thing only, but I'd really like to let it run for days on end while the confuser isn't doing anything else important.
I don't believe there is any way to manipulate the autorelease pool that the system has created, but it may not matter as you can create and release your own autorelease pool in your testing loop.
__________________
~~ Word Flurry ~~ App Store / Website / Facebook
Kalimba is offline   Reply With Quote
Old 05-29-2009, 12:41 PM   #7 (permalink)
Registered Member
 
tawpie's Avatar
 
Join Date: Jul 2008
Posts: 347
tawpie is an unknown quantity at this point
Default

sorry to hijack the thread (it was "stopping", and I want to "start"!)

sleep() doesn't work.

K: I guess I don't know how to separate one pool from another, since all the methods being exercised belong to the mainViewController and use the main pool. Being a lousy programmer, some of my stuff is subclassed but the engine is one "big" class. Are you suggesting I create a pool for my engine?

TIA
__________________
"Hardware will break. Software comes broken" Unknown
Calc-12E <-- ditch your old calculator.
CPR•Choking <-- Review your training, just in case. (Free)
All of Nature NW <-- scrolls in x and y, with pinch zoom AND scrollable text to boot. It can be done ('taint easy tho)
tawpie is offline   Reply With Quote
Old 05-29-2009, 12:44 PM   #8 (permalink)
Former NeXTStep Developer
 
Join Date: Mar 2009
Posts: 997
FlyingDiver will become famous soon enough
Default

Quote:
Originally Posted by tawpie View Post
I am wondering though, if there is a way to safely "force" the draining of main's autorelease pool without returning to the main run loop? I'd like to send the drain message from my mainViewController object...

What I have going is during regression testing I hang in a very tight loop exercising basically all of my methods with randomly varied entry conditions -- which means that I essentially never get back to the main run loop AND my autorelease pool doesn't drain. The issue arises because instance variables created with convenience methods don't drain either and gradually accumulate as crud and eventually it goes boom.

It's not a show stopper as it's a regression test thing only, but I'd really like to let it run for days on end while the confuser isn't doing anything else important.
If you've got a special testing function that loops and calls your methods, you can instantiate your own autorelease pool in the loop. Which would ensure it gets drained once per loop.

joe
FlyingDiver is offline   Reply With Quote
Old 05-29-2009, 12:49 PM   #9 (permalink)
Former NeXTStep Developer
 
Join Date: Mar 2009
Posts: 997
FlyingDiver will become famous soon enough
Default

Quote:
Originally Posted by tawpie View Post
sorry to hijack the thread (it was "stopping", and I want to "start"!)

sleep() doesn't work.

K: I guess I don't know how to separate one pool from another, since all the methods being exercised belong to the mainViewController and use the main pool. Being a lousy programmer, some of my stuff is subclassed but the engine is one "big" class. Are you suggesting I create a pool for my engine?

TIA
Pools are stacked, and depend on the execution path. I suggest creating a pool in whatever code you're using to do your regression testing. Not in the actual production code.

How are you actually doing the testing? What's your test "driver"?

joe
FlyingDiver is offline   Reply With Quote
Old 05-29-2009, 12:59 PM   #10 (permalink)
Registered Member
 
Join Date: Apr 2009
Posts: 13
hcarsten is on a distinguished road
Default

Quote:
Originally Posted by tawpie View Post
sorry to hijack the thread (it was "stopping", and I want to "start"!)

sleep() doesn't work.

K: I guess I don't know how to separate one pool from another, since all the methods being exercised belong to the mainViewController and use the main pool. Being a lousy programmer, some of my stuff is subclassed but the engine is one "big" class. Are you suggesting I create a pool for my engine?

TIA
After running into this problem my solution is something like this :

If you have a "loop" in a separate thread or even the main-thread you can just move the "loop body" to a separate method (instanceMethod: ). Then do

Code:
[self performSelectorOnMainThread:@selector(instanceMethod: ) ...]
as such you will do an "indirect" method call that will go though the main-autoreleasepool "draining". Anyway you will have a small performance degree by the indirection but also by the "draining" itself. Here the operation will NOT run in the background but within the main-loop. So the "indirect" call will return when call all needed "dealloc"-operations are performed.

In case you have a separate thread you can also create your own autorelease-pool and "drain" it e.g. within the loop. Never try to run a "drain" in a separate background thread, but I assume that would not be a good idea.

Carsten
hcarsten is offline   Reply With Quote
Old 05-29-2009, 01:11 PM   #11 (permalink)
Registered Member
 
tawpie's Avatar
 
Join Date: Jul 2008
Posts: 347
tawpie is an unknown quantity at this point
Default

It's my calculator app...

The driver is just another method in the computational engine, one that generates inputs and loops through the various method calls. The keystroke sequence that launches the regression is ifdef'd out for the production build but the idea is to really whack the engine as if the "user" were banging away on the keyboard putting in all kinds of numbers that sometimes make sense and often are not the kind of thing I'd expect them to enter.

And the purpose of the test is two fold: First to make sure nothing changes computationally either because of my fumble fingers or because the OS did something to the math libraries or the hardware ALU is different between devices. Believe it or not, with loan calculations there are sensitivities to how the ALU does the math that can affect its ability to solve a problem. The second is to make sure that the execution time through the computational algorithms doesn't change drastically. On one of my production builds I left an NSLog in by accident and killed my computational performance so I don't want to do that again!

Back to the hijacked subject though. My regression testing is run via a single method in my production code, which in turn calls all of the rest of the stuff. I can build an autorelease pool inside my regression method and thus the convenience-created-autorelease-variables will be swimming in my pool and not the main pool. So then I can safely drain my pool at will? This is a question, I don't know the answer...
__________________
"Hardware will break. Software comes broken" Unknown
Calc-12E <-- ditch your old calculator.
CPR•Choking <-- Review your training, just in case. (Free)
All of Nature NW <-- scrolls in x and y, with pinch zoom AND scrollable text to boot. It can be done ('taint easy tho)
tawpie is offline   Reply With Quote
Old 05-29-2009, 01:16 PM   #12 (permalink)
Registered Member
 
tawpie's Avatar
 
Join Date: Jul 2008
Posts: 347
tawpie is an unknown quantity at this point
Default

Quote:
Originally Posted by hcarsten View Post
After running into this problem my solution is something like this :
[snip]

Carsten
Thanks Carsten, I'll give that a whirl -- it's not too hard and I'll report back.
__________________
"Hardware will break. Software comes broken" Unknown
Calc-12E <-- ditch your old calculator.
CPR•Choking <-- Review your training, just in case. (Free)
All of Nature NW <-- scrolls in x and y, with pinch zoom AND scrollable text to boot. It can be done ('taint easy tho)
tawpie is offline   Reply With Quote
Old 05-29-2009, 01:18 PM   #13 (permalink)
Pro. Game Developer
iPhone Dev SDK Supporter
 
Join Date: Feb 2009
Location: żLa Islas Hermosas?
Posts: 2,176
Kalimba is on a distinguished road
Default

Quote:
Originally Posted by tawpie View Post
...I can build an autorelease pool inside my regression method and thus the convenience-created-autorelease-variables will be swimming in my pool and not the main pool. So then I can safely drain my pool at will? This is a question, I don't know the answer...
Yes, this is exactly what I (and some others) are suggesting. And it's really simple to do this with the following code:
Code:
    // assume this is your main testing loop
    for ( .... )
    {
        NSAutoreleasePool * myPool = [[NSAutoreleasePool alloc] init];
        // do some stuff that creates autoreleased variables
        [myPool release];
    }
__________________
~~ Word Flurry ~~ App Store / Website / Facebook
Kalimba is offline   Reply With Quote
Old 05-30-2009, 06:33 AM   #14 (permalink)
Registered Member
 
Join Date: Apr 2009
Posts: 13
hcarsten is on a distinguished road
Default

Quote:
Originally Posted by tawpie View Post
It's my calculator app...
I can build an autorelease pool inside my regression method and thus the convenience-created-autorelease-variables will be swimming in my pool and not the main pool. So then I can safely drain my pool at will? This is a question, I don't know the answer...
Yes, that would be the way. Just one thing to add. Looking to the docs and users here the basic flawor is something like :

doing an autorelease to any NSObject inheriting object will add the ref. to the last created autorelease-pool. This is conceptional right; basically the pools are managed in a "stack" thereself. So an object-ref is added to top pool on this stack. Once you do a "release" of a pool. It will remove it self from this stack (of course draining all managed objects first).

One thing to add it that EACH thread will have such a pool-stack. Such whenever creating a separate thread. The "pool management" is handled dedicated to the thread.

You can of course create as many pools (and let them stacked) as you like but always be sure to "release" it once you are done. As leaking a pool will in fact also leak any object-refs.
Anyway also the pool release will definetly has a performance impact and it is in fact rather unpredictable.

My personal way is basically to let the UI as most respondible as possible and so try to delegate as much as possible to the main-thread in regards to the autorelease pool. Although I am not sure here how internally the draining is work it might give a chance to postpone the draining to "UI idle" times.

Carsten
hcarsten is offline   Reply With Quote
Old 08-09-2010, 11:05 PM   #15 (permalink)
Registered Member
 
Join Date: Aug 2010
Posts: 1
airjacobs is on a distinguished road
Default

Believe it or not, with loan calculations there are sensitivities to how the ALU does the math that can affect its ability to solve a problem. The second is to make sure that the execution time through the computational algorithms doesn't change drastically.
airjacobs is offline   Reply With Quote
Reply

Bookmarks

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



» Advertisements
» Online Users: 454
16 members and 438 guests
Domele, Duncan C, Feldspar, karatebasker, MacBook MH, Objective Zero, patapple, Paul Slocum, peterwilli, pipposanta, PixelInteractive, Punkjumper, rubyeim54, SLIC, taylor202, Today's Posts
Most users ever online was 1,387, 04-10-2012 at 04:21 AM.
» Stats
Members: 175,694
Threads: 94,137
Posts: 402,950
Top Poster: BrianSlick (7,990)
Welcome to our newest member, peterwilli
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 01:02 PM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.3.0