PDA

View Full Version : When to release object and vars from memory




XcodeNewb
Feb 14, 2009, 11:03 PM
Ok. Well I just finished a pretty large project but the problem is that it may not be so good in the memory management field. I tried to "release" object during development but it would cause the app to crash even when the objects were done being used.

How do you know when the correct time is to release the objects and is there any good tool that will tell you which ones can be released from memory and when it can be done?

Thanks in advance



eddietr
Feb 15, 2009, 01:35 AM
Ok. Well I just finished a pretty large project but the problem is that it may not be so good in the memory management field. I tried to "release" object during development but it would cause the app to crash even when the objects were done being used.


Most likely you are over-releasing the object. You have more releases than retains on that object.


How do you know when the correct time is to release the objects and is there any good tool that will tell you which ones can be released from memory and when it can be done?

Thanks in advance

You should read the Memory Management Programming Guide, it's one of the most important documents that Apple has published for developers.

In general, the correct time to release objects is when you don't need them anymore. Or if you have a low memory condition then you might get even more aggressive about releasing objects that you do sort of "need" still, but which you know you can recreate when needed.

Instruments (specifically the alloc and leaks instruments) is the tool you can use to monitor and optimize your memory usage. Also, setting NSZombieEnabled is a way to help you debug situations where you are over-releasing something.

Hope that helps.

XcodeNewb
Feb 15, 2009, 11:11 AM
Thanks for the info . I read through Apple's guide and thought I understood it but the very first release I added to my code crashed my app. What am I doing wrong?

Current code:

- (void)convertToTwelveHourTime:(NSString *)timeToConvert
{
NSString *hour = [[NSString alloc] init];
NSInteger intHour=0;
hour = [timeToConvert substringWithRange:NSMakeRange(11, 2)];
intHour = [hour intValue];

if (intHour > 12)
{
intHour = (intHour - 12);
currentAmPm = @"pm";
}
else
{
currentAmPm = @"am";
}

if (intHour == 0)
{
intHour = 12;
}

currentDate = [timeToConvert substringWithRange:NSMakeRange(0, 10)];
currentTime = [NSString stringWithFormat:@"%d:%@", intHour, [timeToConvert substringWithRange:NSMakeRange(14, 2)]];
}


I added the release ( since I created the variable 'hour' with the alloc method ) and now the app crashes. What the heck.

New Code:

- (void)convertToTwelveHourTime:(NSString *)timeToConvert
{
NSString *hour = [[NSString alloc] init];
NSInteger intHour=0;
hour = [timeToConvert substringWithRange:NSMakeRange(11, 2)];
intHour = [hour intValue];

if (intHour > 12)
{
intHour = (intHour - 12);
currentAmPm = @"pm";
}
else
{
currentAmPm = @"am";
}

if (intHour == 0)
{
intHour = 12;
}

currentDate = [timeToConvert substringWithRange:NSMakeRange(0, 10)];
currentTime = [NSString stringWithFormat:@"%d:%@", intHour, [timeToConvert substringWithRange:NSMakeRange(14, 2)]];
[hour relase];
}



The memory guide had this example which I worked off of:
- (void)printHello {
NSString *string;
string = [[NSString alloc] initWithString:@"Hello"];
NSLog(string);
[string release];
}


Any ideas how these two are different? Thanks

caveman_uk
Feb 15, 2009, 11:43 AM
The reason it doesn't work is this bit

NSString *hour = [[NSString alloc] init];
NSInteger intHour=0;
hour = [timeToConvert substringWithRange:NSMakeRange(11, 2)];

You're creating a retained NSString instance then you loose all track of it by assigning a new value to the pointer without first releasing the original variable. This is a memory leak. The second object is autoreleased so doesn't need releasing.

XcodeNewb
Feb 15, 2009, 11:51 AM
Thanks caveman. I figured out that by performing the following it fixed the problem:


NSString *hour = [[NSString alloc] initWithString:[timeToConvert substringWithRange:NSMakeRange(11, 2)]];


I am pretty sure I have many more of these in my code that I need to take a look at.

Out of curiousity if I left the code the way it was with the leak and added release statements to the dealloc method would that clear anything up or would I be in the same boat with the leaks still existing? ( This assumes that the hour string was global and not local to this method)

Thanks

admanimal
Feb 15, 2009, 12:14 PM
There is no reason for you to alloc a new NSString object that you have to do memory management on at all. Just do this:


intHour = [[timeToConvert substringWithRange:NSMakeRange(11, 2)] intValue];


or if you really want to use the hour object,


NSString *hour = [timeToConvert substringWithRange:NSMakeRange(11, 2)];
intHour = [hour intValue];


In either case, everything is autoreleased so you don't have to worry about doing it yourself.


Out of curiousity if I left the code the way it was with the leak and added release statements to the dealloc method would that clear anything up or would I be in the same boat with the leaks still existing? ( This assumes that the hour string was global and not local to this method)


Once you overwrite the value of hour with this line from your original code:


hour = [timeToConvert substringWithRange:NSMakeRange(11, 2)];

it is impossible to release the original memory that was allocated for hour because you no longer have any way of knowing where it is (i.e. it's address). The only way would have been if you created another NSString that pointed to the same place as hour before overwriting it.

caveman_uk
Feb 15, 2009, 03:23 PM
Out of curiousity if I left the code the way it was with the leak and added release statements to the dealloc method would that clear anything up or would I be in the same boat with the leaks still existing? ( This assumes that the hour string was global and not local to this method)

Nope, it would still be the same as you've lost track of the retained object. Once you've not got a pointer to it you can't release it properly. Personally I find it better to use autoreleased objects wherever I can so I don't have to worry about them.

XcodeNewb
Feb 15, 2009, 06:55 PM
I definitely appreciate all of your responses and I am using them in trying to clean up my code.

Is there any tool or way to run my application in the Simulator and output to the console or some other area which variables have been declared and have not been released? Is there anything I could do to isolate crashes when they happen and find out exactly what caused the leak.

Thanks again

eddietr
Feb 15, 2009, 09:24 PM
Is there any tool or way to run my application in the Simulator and output to the console or some other area which variables have been declared and have not been released? Is there anything I could do to isolate crashes when they happen and find out exactly what caused the leak.


Yep....


Instruments (specifically the alloc and leaks instruments) is the tool you can use to monitor and optimize your memory usage. Also, setting NSZombieEnabled is a way to help you debug situations where you are over-releasing something.