Archive

Posts Tagged ‘memory management’

Memory Management Pitfalls

May 21st, 2009

I thought that, for the most part, I was done with memory management after moving on from C/C++ to Java. But we all know that was not to be, so I’ve created this quick reference sheet for my own reference that some of you may find useful.

Pitfall 1: The order matters
Assume we have a setter method in some class.

1
2
3
4
5
6
7
8
9
-(void) setText:(NSString *)newValue
{
   if (newValue != text)
   {
      [newValue retain];
      [text release];
      text = newValue;
   }
}

The NSString that is passed into setText may be another NSString. So the value that is passed in must be retained, because we can’t have the memory freed until we are done with the class. We release text because it is being repaced with newValue.

Note that it is wrong the write the code above as

1
2
3
4
5
6
-(void) setText:(NSString *)newValue
{
      [text release];
      [newValue retain];
      text = newValue;
}

This is a due to a somewhat subtle case when text and newValue points to the same instance of NSString. By releasing text, newValue will also be released.

Pitfall 2: Using the dot (’.') notation incorrectly

self.text = newText

is actually a shorthand form of

[self setText: newText]

Thus, it will retain newText, increasing the reference count. Do not confuse it with how it works in a language like Java.

this.text = newText

is different from

self.text = newText

Because the first is a direct assignment and the second is actually a message call.

Pitfall 3: Not following the fundamental rules of reference counting
The fundamental rules are:
1. If you allocate, create or copy it, you need to release it.
2. If you retain it, you need to release it.

Consider the following snippet of code

SomeObject *newObject = [[SomeObject alloc] init];
self.object = newObject;
[newObject release];

newObject needs to be released to balance the retains. The first retain is in the alloc call, and the second retain is in the setObject (aka self.object = newObject) message.

Also, if you write something like this

self.object = [[SomeObject alloc] init];

the retain count will be at 2 because it is retained once for the alloc and one more time for the setObject message.

If you’d like to read more about memory management, here is another post that I wrote about the topic (I also talk about NSAutoReleasePool a bit here).

This wasn’t a comprehensive overview of memory management, but I hope it was somewhat helpful.

If you enjoyed this post, make sure you subscribe to my RSS feed!

Development, Objective-C, iPhone Development , , , , ,

iHappyBirthday 1.1

February 8th, 2009

Fix and a Solution

Thank you to everyone who has purchased iHappyBirthday. Reaction to iHappyBirthday has been quite positive. However, we’ve been receiving reports of random crashes. We actually know why this happens. In a previous, unreleased version of iHappyBirthday, we displayed an alert message to the user telling him or her that the system is running low on memory; and that continuing without freeing up memory may crash the application.

But we removed this message because according to our tests, the phone did not reach such a low level of memory that it would cause it to crash. However, iHappyBirthday 1.1 uses a little bit more memory than 1.0, and that seems to have pushed it over some threshold which is making it more prone to crashing. We are happy to say that we have solved this problem by drastically reducing the memory usage. We have submitted version 1.1.1 and it should be available soon for download. But in the mean time, please follow the workaround from our support page.

Technical Mumbo Jumbo: iPhone Memory Management System

I’m writing this for the benefit of other developers who may be facing similar memory problems. Or if you are not a developer and just happen to be a glutton for pain, then please read on. Our application was not using that much memory, but when other applications (like Safari) were taking up over 20 MB of RAM, it would cause our application to crash due to the phone running low on memory. The following were my observations while chasing down this problem.

When the iPhone runs low on memory, it will start freeing memory from background applications like Safari. But why then was our application still crashing? This was because the rate at which our application was using up the memory was greater than the rate at which the operating system was freeing up the memory. Ultimately, it comes down to this simple fact:

“Always minimize memory usage.”

It’s not very enlightening, but that’s the fact of the matter. Looking at the Activity Monitor in Instruments, I noticed that the memory used by Safari continued to decrease bit by bit over time as iHappyBirthday was running. And then eventually, Safari was entirely removed and all resources freed. However, if iHappyBirthday was too aggressive in its memory usage, even though the OS was freeing up memory, it could not outpace the rate at which iHappyBirthday was requesting memory. The result? Crash.

UIImage!

For version 1.1.1, the memory use was halved. It was achieved by not using the UIImage’s imageNamed message and by intelligently loading resources. It turns out that if you use imageNamed, the resources are cached into the memory and the iPhone does not do a very good job of releasing the cached memory. For version 1.1.1, imageWithContentsOfFile was used in conjunction with imageNamed. And for the most part, the caching was handled by the application rather than the iPhone SDK.

It was interesting to see how the memory management system behaves on the iPhone. And even more enlightening to learn about the pitfalls of using UIImage’s imageNamed routine. In fact, the documentation for this routine states,

“This method looks in the system caches for an image object with the specified name and returns that object if it exists. If a matching image object is not already in the cache, this method loads the image data from the specified file, caches it, and then returns the resulting object.”

But of course, I never looked at the documentation before using this. Had I looked at it, I could probably have avoided all this mess.

So always remember to RTFM!

If you enjoyed this post, make sure you subscribe to my RSS feed!

Development, News and Updates, iPhone Development , , , , , , ,

Free Me from Your Shackled Embrace!

December 15th, 2008

The Problem of Memory Management
Mac OS X Leopard introduced garbage collection, however this feature is missing on the iPhone. Therefore, it is still necessary to manage your own memory through what is known as reference counting.

Reference Counting or Retain Count
Reference counting is actually a very simple idea and has been around for a long time. However, it has a tendency to get tedious when a lot of objects and references are involved.

In Objective-C, every object has a retain count (or a reference count). When an object is created, its retain count is 1. When an object is released, its retain count is 0. When the retain count is 0, the object is deallocated and the memory is freed. As you can see, this is a very simple concept.

We can work through a simple example.

1
2
3
[sam alloc];          // sam has retain count of 1
cindy = [sam retain]; // sam has retain count of 2
[sam release];        // sam has retain count of 1

When the code finishes, sam still has a retain count of 1, so the memory will not be freed. This is because cindy is being clingy and not setting sam free. So in order for sam to be free, we need to release sam one more time.

1
[sam release];      // sam has retain count of 0

AutoRelease
But there is a problem. What if you have a function that returns a newly allocated string? Consider the method below.  

1
2
3
4
5
6
- (NSString)getName
{
   NSString *name;
   name = [[NSString alloc] initWithFormat:@"Robot No. %d", 23];
   return name;
}

In the method above, name will have a retain count of 1 because of alloc and initWithFormat. And when we call the method (or send a message in Objective-C lingo), the caller would generally do this.

1
2
NSString *robotName = [self getName];
[robotName retain];

We retain the value returned by getName because we do not want the object to deallocate before we are done with it. However, this creates a memory leak because the retain count is at 2. We can call [name release]; inside getName right before it returns, but that would cause the retain count to go to 0 and the object would not exist anymore (because it would have been freed).

Meet the NSAutoReleasePool. We can modify the method above to:

1
2
3
4
5
6
7
- (NSString)getName
{
   NSString *name;
   name = [[NSString alloc] initWithFormat:@"Robot No. %d", 23];
   [name autorelease];
   return name;
}<span style="font-family: 'Lucida Grande'; line-height: 19px; white-space: normal;"> </span>

Take note of the line “[name autorelease];“. This line adds this object to the auto release pool. Meaning, the object will not be freed immediately, but rather sometime later in the future. All the objects in the auto release pool are released when the drain message is sent to the auto release pool.

Somewhere near the beginning of your code, you will have the line below.

1
NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];

When the autorelease message is sent to an object, it is added to this pool. When [pool drain] is called, all the objects in the pool are sent the release message.

Remember
The thing to remember is that objects created with alloc, new, copy, mutableCopy or if any function is called that retains the object and increases the retain count, you will have to call a release for each one of those retains.

Any other method will have a retain count of 1, and the object will be added to the auto release pool so you don’t have to worry about those as long as the pool is drained.

Circular Retains
One final note of caution. You must remember to avoid situations where a circular link is created among objects when object A retains object B and object B retains object A. This creates a circular link and creates a retain cycle.

If you enjoyed this post, make sure you subscribe to my RSS feed!

Development, Objective-C, iPhone Development , , , , ,