How can I track down memory peaks? (That's peaks with a p, not an l.) - objective-c

I've got a kiosk app, which, essentially shows a bunch of slides with various bits of information on them. I initially began coding this over a year ago, when I was beginning with Objective-C and iOS development. I find that my code style is much cleaner now than what it was, and I'm much more experienced, so I've decided to rewrite from scratch.
I ran my app with the Allocations instrument to see what the memory usage was. Considering that this is a kiosk app, everything needs to run smoothly, without leaks. (Of course all apps need to run without leaks, but a kiosk app makes this an even more important goal.) I saw some interesting results, so I ran the old version of the code as well.
Running the older version of the code, I see a pretty much even run at about 1.15 megabytes of memory usage. Everything seems to be allocated and deallocated as necessary. In my new implementation, however, I'm seeing something a little different. Memory usage keeps jumping in little "plateaus", and then eventually seems to peak out at about 1.47 megabytes of usage. Here's what the new Allocations report looks like after running for over 10 hours:
I'm concerned for several reason.
The odd pattern in the beginning of the run.
Allocations seems to peak at 1.47 megabytes, but running it overnight shows that it actually will slowly use more and more memory over time. That can't be a good thing.
There are several notable differences between the old project and the new one.
The older one uses Plists as a backing store (I manually read and write to a plist file.) The new project uses Core Data.
The new project implements a library that is called on each "slide" that the old project didn't have. I'd be more concerned about this library, except I wrote it and I went through it to make sure I was releasing everything and only autoreleased wherever manual releases were impossible.
Both classes use a factory class to create the slides. In the old project, the factory class was a singleton. I thought that making it into a normal class would help with the memory issues, since the singleton was never released. (Hence it's properties were not being released.In the new project, the factory class is being released so I'm not sure why it's still taking up all that memory (if that's what's causing the problem.
The old project makes use of string constants in various places. The new code uses a massive enum for the same thing. (The new code in general uses more constants.)
What can I do to track down memory peaks? The memory is all being cleaned up by the application when it discards whatever it's using, but it doesn't seem to be discarding things until the app terminates.
I'd be grateful if anyone would help point me in the right direction.
Edit:
It looks like the peaking is being caused by calls to the KosherCocoa library. If anyone would mind taking a look at it and telling me what I'm doing wrong there as far as memory management goes, I'd really appreciate it.

What can I do to track down memory peaks? The memory is all being
cleaned up by the application when it discards whatever it's using,
but it doesn't seem to be discarding things.
This is a classic case of "abandoned objects" or "usage accretion". That is, you have an application that, as it runs, builds up an object graph in memory as a normal part of usage. The objects aren't leaked because they are still connected to the live object graph. More likely than not, the objects are a part of either some kind of a cache (a write-only cache, most often) or a mechanism involving historical state (the undo stack is a potential source for accretion).
To fix it, you need to make sure your object graph is pruned appropriately as your app runs. Caches should generally use a least-recently-used [LRU] pruning algorithm that limits the cache size. If a cache key ever goes invalid, that data should be pruned, too.
For historical information, pruning the history is critical. So is making sure that the historical data contains an absolutely minimal representation of that historical state.
Use Heapshot analysis -- it was created to help track down exactly these kinds of problems.
I wrote a detailed "How to" guide; When is a Leak not a Leak?

Related

VB.Net Memory Issue

We have an application that has some interesting memory usage issues. When it first opens, the program uses aroun 50-60MB of memory. This stays consistent on 32-bit machines. On 64-bit machines, however, re-activating the form in any way (clicking, dragging, alt-tabbing, etc.) adds around another 50MB to it's memory usage. It repeats this process several times before resetting back to around 45MB, at which point the cycle begins again.
I've done some research and a lot of people have said that VB in general has pretty poor garbage collection, which could be affecting the software in some way. However, I've yet to find a solution. There are no events fired when the application is activated (as shown by 32-bit usage) - the applications is merely sitting awaiting the user's actions.
At load, the system pulls some data into a tree view, but that's the only external connection, and it only re-fires the routine when the user makes a change to something and saves the change.
Has anyone else experienced anything this strange, and if so, does anyone know of what might fix it? It seems strange that it only occurs under x64 systems.
One of the best ways to start looking for what causes the leak is with a profiling tool.
http://www.jetbrains.com/profiler/
These guys have a 10 day free trial which is normally enough to figure out the area of the code that is causing your problems.
This doesn't sound like a problem at all. As mentioned in the comments, 64 bit programs will use more memory. The application doesn't use much memory, and it gets recovered after a while. VB.net doesn't have "pretty poor garbage collection", it uses the same collector as c#, the CLR's collector.

Best practice testing the iOS application development with Instruments

I wonder how the professional application that provided to customer is such elegant , smooth and less or no application crash. because I always see the problem is mostly about memory leaking, NSZombie or not good enough performance.
I see it's great to fix some problem with Instruments Tool. But I just be familiar with memory leaks and zombie template. Of course, I think there are other interesting tool to trace and fix our application better. (System usage, Automation Testing, etc.. Any ideas?)
My question : What's the best strategy to sharp your application with Instruments? Recommend instruments template or any suggestion?
Let's share your experience and discuss!
*UPDATE : * May I ask more question, Should I edit this question to the wiki? It should be more than question that we can share strategy.
I mainly (about 98.2% of the time) use the Leaks and Allocations templates. Also, many people don't know - but in Xcode 4, you can start the app using instruments right from Xcode. From the top menu, just choose Product -> Profile.
Also - even when using ARC, you should still be conscious of how you are using memory and how you are allocating objects. Many times, ARC was doing its thing just fine and yet a small programming change in my code resulted in much less allocated objects. ARC will help you when writing code, but it is not an excuse for not testing and profiling your applications to make them as efficient as possible.
Yes, Instruments is critical. ARC mitigates some of the worst memory problems. Analyze (on Product menu) is also under-appreciated, too.
Check out program 123, Improving the Stability of Your Apps, in WWDC 2011 in the App Frameworks section, which has a nice discussion of other issues that can affect the stability of your code (I especially think the discussion of testing is good).
Finally, elegance is not a product of a tool, but rather of good design. It takes a surprisingly amount of work to make a product that is elegant. Embrace the HIG and the broader philosophical themes contained therein. Also, do code and design reviews with developers that you respect.
The CPU sampler (Time Profiler) will tell you where your program is spending its execution time. If your app is 'slow', this instrument can often help you determine where the problem time consumers are, and (if you understand your program) how you can remedy those problems.
Run this instrument regularly in order to understand your programs as well as the implementations behind the abstractions they depend on -- don't wait until a problem arises.
You can use the CPU sampler to record the callstacks of your programs' threads. This is recorded at a high frequency. The sampler displays information such as the functions that are taking the most time and what percentage of the time they are taking. You can charge libraries or functions to their callers, effectively choosing the granularity you'd like, or hiding what you cannot alter. Once you've found the functions/methods you are interested in, you can view the source file in Instruments, and it will break down what's taking so long for you.
Apple introduced sweet feature called Automatic Reference Counting(ARC) that makes almost all memory control for you. You just need to set weak/strong parameter of properties. And it eliminates almost all problems with memory leaks.
And as for tools - I don't know any other app other than Instruments. Instruments has all... Instruments:) I need, to do tests with.

Why is my app full of memory leaks after migrating to ARC?

After migrating my app to ARC using the migration tool and resolving all pending issues a quick test in the Allocation instrument revealed that pretty much anything I do in the app is leaking memory.
It's a pretty big app and migration took 2 hours to complete (including checking every change which I did - all of them looked fine!)
I checked all the compiler flags twice to make sure ARC is really enabled for every file and on the project level.
Previously to migrating to ARC my app was totally fine. There was absolutely no heap growth when taking Heapshots by repeating the same action multiple times. It was 100% leak-free, there was no abandoned memory. It was perfect. Now it's one huge leaking thing like if there was no tomorrow.
Any idea what's going on?
You haven't shown any code here to highlight parts of your application that are causing objects to accumulate in memory, so it's hard to provide a specific answer to your situation. However, there are some broad suggestions that I can provide based on my experience in migrating several projects across on Mac and iOS.
In another answer, I describe in detail several areas of memory management that you'll still need to watch out for under automatic reference counting. The primary concerns here are retain cycles and Core Foundation objects (or other non-Objective-C memory allocation).
Given that you had an application which did not accumulate memory on repeat actions before and was cleanly ported through the ARC migration tool, retain cycles are more likely the problem than improper bridging, etc. with Core Foundation. The migration tool tends to highlight problematic areas with Core Foundation and catch those before they become an issue. How to deal with them may be tricky, but you at least know they're there.
Retain cycles can be subtle bugs to track down. Look for delegates that are set using strong instance variables or properties, rather than weak or unsafe-unretained ones. Examine your use of blocks or block-based notification observers, because they can hold on to references to the objects that create them (particularly in the case of the observers) and create cycles. Check for objects further down a navigation hierarchy that use strong references to point to ones higher up.
Use Instruments to track down the specific objects that are accumulating via the Leaks and Allocations tools. In the latter, use heap shots between repeated actions to see which objects are created and still alive after each pass. You should also be able to identify where those objects are allocated, hopefully leading back to what's grabbing an incorrect strong reference.
The Leaks instrument has a new retain cycles detector, which can be seen by going to the lower panel and changing the "Leaks" popup to "Cycles & Roots". This doesn't catch everything, but it can help.
I've now moved multiple projects on Mac and iOS to ARC, including Mac applications that had been using GC, and in each case the applications have been better off for it. The process has exposed bugs that I had missed for years in my memory management, cut on average ~3% of my project code, and has led to some significant performance increases in my previously garbage collected Mac applications (I haven't benchmarked my iOS ones yet).

How important is managing memory in Objective-C?

Background: I'm (jumping on the bandwagon and) starting learning about iPhone/iPad development and Objective-C. I have a great background in web development and most of my programming is done in javascript (no libraries), Ruby, and PHP.
Question: I'm learning about allocating and releasing memory in Objective-C, and I see it as quite a tricky task to layer on top of actually getting the farking thing to run. I'm trying to get a sense of applications that are out there and what will happen with a poorly memory-managed program.
A) Are apps usually released with no memory leaks? Is this a feasible goal, or do people more realistically just excise the worst offenders and that's ok?
B) If I make a NSString for a title of a view, let's say, and forget to deallocate it it, does this really only become a problem if I recreate that string repeatedly? I imagine what I'm doing is creating an overhead of the memory needed to store that string, so it's probably quite piddling (a few bytes?) However if I have a rapidly looping cycle in a game that 'leaks' an int every cycle or something, that would overflow the app quite quickly. Are these assumptions correct?
Sorry if this isn't up the community-wiki alley, I'm just trying to get a handle on how to think about memory and how careful I'll need to be. Any anecdotes or App Store-submitted app experiences would be awesome to hear as well.
I've taught courses on Cocoa development, and memory management is the second thing I teach (the first being C pointers). My experience has been that if a Cocoa programmer doesn't understand memory management, then he never amounts to much of a Cocoa programmer.
In other words, learn memory management. You won't regret it.
Follow the patterns, and memory management is rarely the biggest roadblock in Cocoa.
However, I'm going to be a contrarian here: your sense is mostly correct. Leaking one NSString used as a label somewhere is not going to hurt anybody. Most apps of any complexity have multiple singletons around in the world holding state for the entire life of the app, and that's OK too (well, better, because it's explicit). So no, accidentally leaking a string once isn't going to kill you. Leaking big things (images, textures, file content data) will hurt you, though-- Apple doesn't guarantee any minimum or deterministic amount of memory for your process on the iPhone OS platform, so one or two of those leaks might result in users seeing frequent "crashes" in the field that you don't always see during development.
Be vigilant, use the patterns, and use the tools, and you'll be OK.
Your should never leak memory.
Consider: You today write some code that leaks memory only once during the execution of a program. Tomorrow, you reuse that code in some other way and it is executed many times. The leak is then problematic. Finding that leak may be very difficult. Much more difficult than making sure to always free your memory the first time you wrote the code.
Save yourself and others a headache down the road: always free your memory.
It is very important. Apple offers a tool for memory leak detection called Instruments.
This topic has previously bean discussed here as well: Memory leak detection tools in XCode
More important than life itself :p
Seriously though, just follow the rules in the links below and you'll be ok.
It becomes second nature after a while.
http://theuntitledblog.com/2010/05/25/objective-c-memory-management-rules/
http://developer.apple.com/iphone/library/documentation/cocoa/Conceptual/MemoryMgmt/Articles/mmObjectOwnership.html

Is garbage collection used in production quality Cocoa apps?

I'm mainly wondering about the affect that garbage collection would have on performance. Is the use of garbage collection frowned upon for release apps?
Another concern that I can think of is that using garbage collection could lead to sloppier programming.
Do you use garbage collection in your apps?
Garbage Collection is used in many production quality applications. Xcode, Automator, System Preferences and several other system applications are GC'd, and you can expect that trend to continue over time.
As well, many developers have embraced GC and are using it exclusively in their applications. Intuit's new versions of Quicken and QuickBooks for the Mac are garbage collected, for example.
There are a number of advantages of GC, too. Off the top of my head and from personal experience:
it makes multithreading easier; a simple assign is an atomic declaration of ownership
it offloads a bunch of memory management to other cores; it is naturally concurrent and offloads a bunch computation from the main thread (or computation threads)
in many cases, allocation and deallocation can happen entirely within the context of a thread, thus eliminating any need for global synchronization or locking
the collector has gotten faster with each release of Mac OS X and that trend will continue (just as it has with the rest of the system). By offloading more of your app's computational load to the system provided frameworks, your app will gain more and more from optimizations to the underlying system.
because the collector has intimate knowledge of the object graph -- of the pointers between objects -- in memory, it makes analysis and debugging significantly easier. Instead of "where did this dangling pointer come from?", the question is now "Give me a list of reasons why this object is sticking around longer than I think it should?".
This isn't to say that there isn't work to do to make your application work optimally under GC. There certainly are such tasks!
Garbage collection has been around since the 1960s and is used in many released applications. All .NET apps use garbage collection. Apple uses libauto in Xcode.
Garbage collection generally leads to better quality apps in Cocoa since the developer is freed from the memory management burden. There are tons of Cocoa apps that leak! (though it may not a significant amount of memory)
I tend to use gc since since I can turn around my apps faster and don't have to worry about messaging zombie objects!
I use GC whenever I can, because the best code of all is the code you don't have to write in the first place. Also, as Bbum pointed out above, running under GC means that you have far more information available for performance analysis, should you need to debug any bottlenecks.
Garbage collection is recommended for any new Cocoa applications, and Apple eats its own dog food by using it in Xcode. Performance is an interesting situation, because while you're most likely going to be consuming more CPU cycles overall, the application may actually end up faster in some areas due to multithreading of the collector and the simplification of accessor methods.
Computers are made to do work for us. Cocoa's reference counting is usually easy to manage, but garbage collection is one more thing it can do now--let the machine do the work so you can focus on things that matter!
Like the others, I would strongly recommend using GC. The performance overhead usually is negligible! I don't need to repeat the benefits as stated by other users.
However, I would strongly encourage writing libraries, as opposed to applications, to run in a non-GC mode as well. Some environments cannot run GC code, the iPhone being the notable one; so if you created an internal library for yourself, that you envision reusing it later for an iPhone app, then I would recommend designing it so it would work in a non-GC environment as well.
Converting a GC code to non-GC code is much more difficult than the other way around!