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
Related
I'm still a newb to objective C and Xcode 5. I have made a simple game and was performing some analysis on the game's memory leaks using one of Xcode's built in performance tools (Cmd+I). To make the game I was using cocos2D framework.
Now it looks like I had quite a few memory leaks (screenshot below). A few things I wanted to address were (keep in mind it's a really small game)
Are the memory leaks being shown significant? Or is it normal to have a few memory leaks in the bytes-kbytes range?
Many of them are "Malloc -" and have no trace in the Extended Detail view. How do you deal with these?
I know Xcode has the option to turn on Objective-C ARC. Would it be a better idea for me to just turn that on instead of worrying about keeping track of memory leaks and all of that? (keep in mind I'm a newb)
Thanks, here's the screenshot!
I think the more important thing about memory leaks is how often does it occur. If it happens on app load once, i don't think it will matter that much, but if it happens in a loop or after every user action then I think it is something to be worried about.
And I definitely recommend using ARC, that question has been posted to SO many times, here you can find better answers than I could ever give.
ARC, worth it or not?
To ARC or not to ARC? What are the pros and cons?
To use Automatic Reference Counting or not to use
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.
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?
I'm starting to build a real-time raytracer for iOS. I'm new to this raytracing thing, all I've done so far is write a rudimentary one in ObjC. It seems to me that a C-based raytracer is going to be faster than one written in ObjC, but the ObjC one will be far simpler, as object hierarchies come in very handy. Speed is very important, though, as I want it to be real-time, say 30 fps.
What's your opinion on whether the speed up of C be worth the extra complexity? I can forsee the C code taking much longer and causing me headaches with lots of bugs (although I'm not new to C), but going for more speed is seductive initially.
Are there any examples out there of raytracers written in C? My google search for such things is contaminated with lots of results for C++ and C#.
If you want fast ray tracing, you can pretty much forget about using either C or Objective C. You almost certainly want to use OpenCL. It's still not going to be enough to get you (even very close to) 30 fps, but it'll probably be at least twice as fast as anything running on the CPU (and 5-10 times faster wouldn't be any real surprise).
as zneak stated, c++ is the best combination for speed and polymorphism.
however, you can accomplish something close by reducing the objc calls (read: reduce the polymorphic interface to the minimum set required, then just putting the parts that need to be fast in plain c or c++).
objc message dispatch is quite fast, and you can typically remove much of the virtual/dynamic methods from your interfaces (assume every objc instance method is virtual). c code in objc methods is still c code... from there, determine where your bottlenecks are -- it doesn't hurt to profile before changing working code, either ;)
Writing a "realtime Raytracer" is without the use of Hand-Optimized Assembly (or the use of the "cheap" Intel compiler ;) , but this is not possible for this platform), impossible because you need the speed.
Further more you need a lot of Processing power but i guess even the OpenCL path is not powerful enought (this is in my opinion the case even for real Desktop machines, the reason for this is the lack of an real big cache on the Graphics Processor).
Have a look through http://ofps.oreilly.com/titles/9780596804824/ that is as close as you'll get.
It isn't ray tracing, I have written a ray tracer and it is a huge amount of work. GL uses a different technique for graphics, hence it will be unable for example to render the capacity of a diamond to capture light. that link contains sample code, you can download and run it. You will realise that even some of the moderately complex examples really chug on an actual device... we are talking < 1 fps.
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!