Do I no longer have to worry about memory management iOS 5 onwards? Also, will all programs written for iOS 4 and earlier versions have to be rewritten to allow iOS to manage the memory for you?
You appear to be talking about Automatic Reference Counting, mentioned in other answers. ARC is a kind of GC in that it automates memory freeing, but has a number of differences from a good garbage collector.
Firstly, it's mainly a compiler technology. The compiler knows about Cocoa's reference-counting guidelines, so it inserts retains and releases where they should be according to the rules. It works just like if you'd written the retains and releases yourself — it simply inserts them for you. Normal garbage collectors keep track of your program's memory while it is running.
Second, since it is just like retain and release, it can't catch retain cycles (if Object A retains Object B and Object B retains Object A, and nothing else references either of them, they both become immortal). You need to take the same precautions to prevent them.
It also uses resources differently from an automatic garbage collector. The garbage collectors used with Objective-C have to scan for unreferenced memory and collect it — which is expensive, and can lead to "stuttering" on slower systems — but they only have to do this occasionally, and in theory can even fine-tune their collection cycles to match how a program actually uses its memory. In general, a GC program will use more memory than a non-GC program and will slow down significantly when the GC decides to collect. ARC, on the other hand, moves the "scanning" to compile-time and frees memory as soon as it's available, but it has to constantly update object reference counts instead of waiting for garbage to build up like a collector.
On Apple's public iOS 5 page, they state:
Automatic Reference Counting
Automatic Reference Counting (ARC) for Objective-C makes memory management the job of the compiler. By enabling ARC with the new Apple LLVM compiler, you will never need to type retain or release again, dramatically simplifying the development process, while reducing crashes and memory leaks. The compiler has a complete understanding of your objects, and releases each object the instant it is no longer used, so apps run as fast as ever, with predictable, smooth performance.
It's a compiler feature; not an OS feature so I don't see why it wouldn't work with older versions.
Automatic Reference Counting
implements automatic memory management
for Objective-C objects and blocks,
freeing the programmer from the need
explicitly insert retains and
releases.
You will worry less about memory management. There is public info available on the subject:
ARC replacing GC? (lists.apple.com)
Automatic Reference Counting (clang.llvm.org). This is the tech spec on ARC.
If the spec is too harsh to read, in short, you will need to edit the retain/release code to use ARC, but old programs remain compatible. What you shouldn't do is mix both.
Related
With the new automatic reference counting (ARC) introduced in Xcode 4.2, we no longer need to manually manage retain / release in Objective-C.
This seems similar to garbage collection, as done in Objective-C on the Mac, and in other languages. How does ARC differ from garbage collection?
As I describe in my answer here, ARC can provide the best of both manual memory management and tracing garbage collection. It mostly removes the need for a developer to track manual retains, releases, and autoreleases on Objective-C objects, yet avoids the need for a garbage collector process which can use up limited resources on a mobile device and cause occasional stutters in a running application.
ARC inserts the appropriate retains and releases required for reference counting at compile time, by applying the rules that all Objective-C developers have had to use over the years. This frees the developer from having to manage this themselves. Because the retains and release are inserted at compile time, no collector process is needed to continually sweep memory and remove unreferenced objects.
One slight advantage that tracing garbage collection has over ARC is that ARC will not deal with retain cycles for you, where tracing garbage collection can pick these up.
A great read on the subject comes from this thread on Apple's Objective-C mailing list, where Chris Lattner has this to say:
The primary advantage of GC over ARC is that it collects retain
cycles. A secondary advantage is that "retained" assignments are
"atomic" because they are a simple store. ARC has several big
advantages over libauto GC:
It has deterministic reclamation of objects (when the last strong reference to the object goes away) where GC frees an object "sometime
later". This defines away a class of subtle bugs that can exist in GC
apps that aren't exposed because the collector doesn't trigger "in the
buggy window".
The high water mark is generally much lower with ARC than GC because objects are released sooner.
libauto provides a fragile programming model, you have to be careful to not lose write barriers etc.
not all of the system frameworks are GC clean, and the frameworks do occasionally regress as they evolve.
ARC doesn't suffer from false roots. libauto conservatively scans the stack, which means that integers that look like pointers can root
object graphs.
ARC doesn't have anything that kicks in and stops your app, causing UI stutters. libauto is pretty advanced as far as GC implementations
go because it doesn't immediately stop every thread, but it still does
usually end up stopping all the UI threads.
I am currently migrating both my manually memory managed projects, as well as those using Objective-C garbage collection, to ARC. After using garbage collection in a couple of Mac applications for a while now, I see some significant advantages in moving these projects to ARC.
ARC rely on a compile time "referenced" objects which make it efficient in a low-power mode environments (Mobile devices).
GC rely on a runtime based "reachable" objects which make it efficient in a multi-threaded environment.
Operation
ARC injects a code into the executable to be executed "automatically" on unused objects depending on their reference count.
GC works in the runtime as it will detect the unused object graphs (will eliminate retain-cycles) and remove them on an indeterminate time intervals
Advantages of Automatic Reference Counting
Real-time, deterministic destruction of objects as they become
unused.
No background processing.
Advantages of Garbage Collection
GC can clean up entire object graphs, including retain cycles.
GC proceed in the background, so less memory management work is done
as part of the regular application flow.
Disadvantages of Automatic Reference Counting
ARC cannot handle retain cycles automatically.
Disadvantages of Garbage Collection
Because GC happens in the background, the exact time frame for object
releases is undetermined.
When a GC happens, other threads in the application may be
temporarily put on hold.
How does ARC differ from garbage collection?
ARC is a form of garbage collection.
You probably mean "what is the difference between ARC and tracing garbage collection (like the JVM and .NET)?". The main differences are that ARC is slower and leaks cycles. That's why the JVM and .NET both use tracing garbage collectors. For more information, please read How do reference counting and tracing garbage collection compare?.
the short and sweet answer is as follow:
GC of java is Runtime, while ARC is compile time.
GC has reference to the objects at runtime and check for the dependencies of object runtime.
While ARC appends the release, retain, autorelease calls at compiletime.
I'm performance tuning my iPhone/iPad app, it seems like not all the memory gets freed which should be. In instruments, after I simulate a memory warning in my simulator, there are lots of "Malloc" entries left; what's about them? Can I get rid of them, what do they mean/what do they stand for?
Thanks a lot,
Stefan
At any time, your app will have a (huge) number of living objects, even after getting a memory warning (and the subsequent memory recovery by the operating system). So, it is pretty common that you will also see many of those mallocs you are seeing.
They are not in themselves a sign that something is wrong with memory allocation, but possibly only of the fact that your program is running.
Also have a look at this S.O. topic to learn more about the object allocation tool.
Furthermore, there are many advanced techniques you can use to detect memory allocation problems.
Here you can find a great tutorial that will allow you to go way beyond what the Leaks tool allows you to.
EDIT:
About the exact meaning of those mallocs, you have to think that you can allocate two broad classes of objects (to put it roughly): Objective-C objects that are created through the Obj-C runtime system, and "normal" C objects, that are allocated through malloc.
Many object of the second class are allocated (without you directly calling malloc) by system libraries and by the compiler C library (think about, e.g., sockets or file handles, whatever). Those (C) objects do not have type information associated to them, so Instruments simply shows you the size of the allocated memory block, without having more information available.
Many times malloc objects are created by higher-level classes, so that when you recover memory associated to their instances, also memory allocated through malloc is freed.
You should not worry specifically about them, unless you see that their overall size "grows indefinitely" along program execution. In such case you need first to investigate the way you alloc/release your higher level objects and understand where in your code things get stuck.
I have a method which needs to run in its own thread 88 times per second (it's a callback for an audio unit.) Should I avoid creating an NSAutoreleasePool each time it's called?
Creating the NSAutoReleasePool itself shouldn't be too slow, but if there are a lot of objects to be dealloc'ed when you 'drain' the pool, that could start get slow. It's probably worth profiling how long the pool drains are taking.
Assuming that you've just come back from Instruments or Shark with concrete evidence that autorelease pools really are a performance concern in your app…
Creating your own autorelease pools is an answer to a dilemma. You do it when you are creating a lot of objects, in order to not create too many at once and either enter paging hell (on the Mac) or get a memory warning and/or termination (iPhone OS).
But autorelease pools are objects, too. They aren't free. The expense of a single autorelease pool is tiny, but in a loop where you're creating lots of objects, you're probably creating one pool every X objects,
draining it, and creating another one for the next X objects.
Even then, the autorelease pools probably aren't that many and so won't add up to much. You should see this in your Instruments or Shark profile: Most of the time spent in -[NSAutoreleasePool drain] is, in turn, spent in -[NSObject release]. That's time you'll be spending whether you use an autorelease pool or not.
[EDIT: As of December 2011, autorelease pools can now be created without an object, with the #autoreleasepool statement. They probably are still not free (at least without ARC), but now they are even cheaper than before.]
So the real solution in such cases is simply to create fewer objects. This can mean:
Using and reusing buffers whenever possible, reallocating a previously-used buffer when the size needed changes. You may want to use the malloc_good_size function to round up the size, to make it less likely that you'll need to reallocate (you can skip reallocating if the old needed size and new needed size both round up to the same number). You may also consider only growing the buffer, never shrinking it.
Using and reusing mutable objects. For example, if you build up a string and then write it out to a document, instead of releasing it and creating a new one, delete its entire contents, or replace the entire old contents with the first portion of the “new” string.
Adjusting the value of X (your pool-disposal threshold). Higher X means more momentary memory consumption, but fewer pools created and thrown away. Lower X means more pools, but less risk of paging out or getting a memory warning. This is unlikely to make much of a difference except when you raise X too far, or lower it from being too high.
Please see Mike Ash's Performance Comparisons of Common Operations. When he tested in 10.5, creating and destroying an autorelease pool took 0.0003577 milliseconds.
If you can avoid it, do that. If you can’t, there’s no need to worry about it, autorelease pools are created and released quite quickly. If you need a precise answer, set up a simple test and measure (which is always a good idea when speaking about performance).
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?
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.
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.
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.
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
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.
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.
I've been looking at LLVM for quite some time as a new back-end for the language I'm currently implementing. It seems to have good performance, rather high-level generation APIs, enough low-level support to optimize exotic optimizations. In addition, and although I haven't checked it myself, Apple seems to have successfully demonstrated the use of LLVM for garbage-collected multi-core programs.
So far, so good. As I'm interested in both garbage-collection and multi-core, the next step would be to choose a LLVM multi-core-able garbage-collector. Which brings me to the question: what is available? I'm aware of Jon Harrop's HLVM work, but that's about it.
Note that I need cross-platform, so Apple's GC is probably not what I'm looking for (unless there's a cross-platform version). Also note that I have nothing against stop-the-world garbage-collectors.
Thanks in advance,
Yoric
LLVM docs say that it does not support multi-threaded collectors yet.
As the matrix indicates, LLVM's
garbage collection infrastructure is
already suitable for a wide variety of
collectors, but does not currently
extend to multithreaded programs. This
will be added in the future as there
is interest.
The docs do say that to do multi-threaded garbage collection you need to stop the world and that this is a non-portable thing:
Threaded
Denotes a multithreaded mutator; the collector must still stop the
mutator ("stop the world") before
beginning reachability analysis.
Stopping a multithreaded mutator is a
complicated problem. It generally
requires highly platform specific code
in the runtime, and the production of
carefully designed machine code at
safe points.
However, shared state between threads is a nasty scaling issue. If your language communicates solely through message passing between 'tasks', and therefore there was no shared state between worker threads, then you could use a per-thread collector for the per-thread heap?
The quotes that Will gave are about LLVM's intrinsic support for GC, where you augment LLVM with C++ code telling it how to walk the stack, interpret stack frames, inject read and write barriers and so on. The primary goal of my HLVM project is to become useful with minimal effort and risk so I chose to use the shadow stack for an "uncooperative environment" in order to avoid hacking on immature internals of LLVM. Consequently, those statements about LLVM's intrinsic support for GC do not apply to HLVM's garbage collector because it does not use that infrastructure at all. My results are extremely compelling: you can achieve excellent performance with minimal effort (serial performance and parallel performance).
I believe HLVM already runs out-of-the-box across Unixs including Mac OS X because it requires only POSIX threads. I strongly disagree with the claim that writing a stop-the-world GC is difficult: it took me 5 days to write a 100-line multicore garbage collector and I barely know anything about computers. I cannot believe it would be difficult to port to Windows either.