views:

453

answers:

6

I'm running through some memory profiling for my application in SDK 3.2 and I used the 'Leak' profiler to find all my memory leaks and I plugged all of them up. This is a scrollView navigationController application where there are tiles and you click a tile which goes to a new view of tiles and so on, I can go many levels deep and come all the way back to the top and the 'Leak' profiler says everything is cool.

However, if I watch the memory footprint in the 'ObjectAlloc' profiler the memory footprint goes up and up as I go deeper (which seems reasonable) but as I back out of the views the memory footprint doesn't go down as I'd expect.

I know this is a vague description of the app but I can't exactly post a gillion lines of code :) Also it should be noted I'm using coreData to store image data as I go so the database is growing in size as more nodes are chosen, dunno if/when that is released from memory.

What gives?

+2  A: 

Depending on how you have your object graph constructed in Core Data, it's memory use can grow unexpectedly large.

A common mistake is to store objects inside a complex and often faulted (loaded into memory) entity. This cause the big blob to be loaded/remain in memory whenever any other part of the entity is referenced. As you object graph grows, it eats more and more memory unless you actively delete objects and then save the graph.

For example: You have an person entity with lots of text info e.g. name, address, etc as well as a large photo. If you make the photo an attribute of the person entity it will be in memory anytime the person entity is faulted. If you get the attribute name, then the photo attribute is in memory as well.

To avoid this, blobs should be in their own entity and then linked to other entities in relationships. Since relationship objects are not faulted until they are called directly they can remain out of memory until needed.

TechZen
I made a point of doing this in my object graph, all images have their own entities. However if I'm adding lots of new items to coreData, including images, the image data is in memory since I just added it, how can I 'de-fault' something to remove the entity from memory?
Shizam
Found entries on 're-faulting', giving it a go.
Shizam
Not sure if this applies to your app and if it does you've probably covered it anyway but you should only load full size images when you need a full sized image. E.G. a tableview will display a full sized image of many megs in a thumbnail in a row cell. It looks visually small but memory wise, it enormous. If possible you should create and store thumbnails which only have enough resolution for the size they actually appear at. Then only load the full images exactly where they are needed and dispose them immediately after.
TechZen
Thanks for the suggestion and yes thats what I do, I store 2 image sizes, a thumbnail and a fullsized image and only show the fullsized image if they go to view it.
Shizam
Turns out my problem wasn't related to coredata its related to setBackgroundImage for a button, for some reason its not releasing the memory for an image I assigned to it even if I release the living crap out of the UIImage. And it looks like some other people are having a similar problem.
Shizam
You should create an answer, put your solution in it and check mark it so others can find it easily. They won't see it buried down here in the comments. You're allowed to answer your own question.
TechZen
A: 

You can have a continuously growing program without necessarily leaking memory. Suppose you read words from the input and store them in dynamically allocated blocks of memory in a linked list. As you read more words, the list keeps growing, but all the memory is still reachable via the list, so there is no memory leak.

Jonathan Leffler
+1  A: 

Just because there are no refcount-based leaks, doesn't mean that you're not stuffing something off in a Dictionary "cache" and forgetting about it; those won't show up as leaks because there are valid references to it (the dict is still valid, and so are the refs to all its children). You also need to look for valid, yet unnecessary refs to objects.

The easiest way is to just let it run for too long, then sort object counts by type and see who has a gigantic number - then, track down the reference graph (might be hard in Obj-C?). If Instruments doesn't do this directly, you can definitely write a DTrace script to do so.

Paul Betts
+1  A: 

To reiterate:

char *str1 = malloc(1000);
char *str2 = malloc(1000);
  .
  .
  .
char *str1000 = malloc(1000);

is not a memory leak, but

char *str1 = malloc(1000);
char *str1 = malloc(1000);  //Note! No free(str1) in between!

is a memory leak

Arthur Kalliokoski
Thanks, I understand that difference. My issue here is I'm creating child views (and watch the memory increase) then releasing all the views correctly (but the memory footprint doesn't decrease). And the more I think about it the more I think its related to adding new information to coreData.
Shizam
A: 

The information on core data memory management is good info and technically the answer by Arthur Kalliokoski is a good answer re: the difference between a leek and object allocation. My particular problem here is related to an apparently known bug with setBackgroundImage on a button in the simulator, it creates a memory 'leak' in that it doesn't release ever release the memory for the UIImage.

Shizam
+4  A: 

This sounds like it could be one of a few things:

  • Memory not given back to OS after deallocation. This is a common design for C runtimes. When you do an allocation the C runtime allocates more memory for its use and returns a chunk of it for you to use. When you do a free the C runtime simply marks it as deallocated but doesn't return it back to the OS. Thus if the Leak Tool is reading OS level statistics rather than C runtime statistics the Leak tool will fail to report a corresponding decrease in memory usage.

  • Misleading values reported by Leak Tool Memory. The Leak Tool could be looking at different values than the C runtime and is reporting values that will cause you concern even though nothing is wrong (just as people try to use Task Manager in Windows for detecting leaks and get very confused with the results because it is a very poor tool indeed for that job).

  • Fragmentation. It is possible that your application is suffering from memory fragmentation. That is when you allocate, then deallocate then allocate, subsequent attempted allocations are larger than the "holes" left by deallocations. When this happens you fragment the memory space, leaving unusable holes, preventing large contiguous memory blocks and forcing the usage of more and more memory space until you run out of memory. This is a pathological condition and the fix is typically application specific.

I think the first of these three suggestions is most likely what is happening.

Stephen Kellett