XCode/Instruments not showing memory leaks - objective-c

I'm following the Stanford iOS development lectures and I have a Calculator brain class which has been alloc init in a controller but I haven't released it in the dealloc.
- (CalculatorBrain *)brain
{
if (!brain)
brain = [[CalculatorBrain alloc] init];
return brain;
}
I ran from XCode -> Run with Performance Tool and the app started and no leaks appeared, I then clicked the home button in the iOS Simulator and nothing, I then double clicked the home button and closed the app and still nothing.
I also did Build & Analyse and it didnt spot anything
Could you let me know why its not picking it up?

It appears as if there is no detectable leak. Look at this line:
brain = [[CalculatorBrain alloc] init];
As long as brain points to an object, that object won't be considered a "memory leak". If at some point you do this,
brain = nil;
Then the leak will register. Deallocating the container object will also achieve this, but are you sure it's being deallocated? (It won't be deallocated when your program exits, for example.)
The problem: Leak detectors cannot detect all memory leaks -- this is a mathematically proven fact. Most detectors only detect unreachable objects, and many leak detectors are especially susceptible to false negatives -- in C it is hard to tell the difference at runtime between a pointer and an integer.
Edit: It sounds like your application only ever creates one instance of the controller, which only creates one instance of CalculatorBrain. If you think about what a memory leak really is, you can define it as unused memory that your program does not release back to the operating system.
While the program is running, CalculatorBrain is always in use and therefore it is not a leak.
When the program exits, the operating system automatically reclaims all memory used by your process, therefore there cannot be any memory leaks after a program exits.
If you want to create a leak to see what it looks like, you could create a new CalculatorBrain multiple times while your program is running, but forget to release the unused versions. In this scenario, as your program runs, more and more instances of CalculatorBrain would accumulate. On iOS and other embedded systems, this will generally crash your program. On a modern 64 bit computer it will gradually fill up the available swap space until you run out of swap, address space, or some other resource -- causing the program to crash or making the system very unresponsive.
Standard practice is to not care about deallocating objects which are supposed to exist for the entire program's run.

The analyzer cannot find all memory leaks. As far as it is concerned, storing the instance into the ivar doesn't leak it from that method, and then in dealloc it doesn't realize that the ivar should be released. XCode 4 may have improved in this respect, I don't recall (I still use XCode 3 myself).
As for the performance tool, remember that an object won't be considered leaked until nothing holds a reference to it anymore. So even though your controller doesn't deallocate the brain, the brain won't be considered leaked until the controller is deallocated (or receives a brain transplant). Also, note that on *nix-like systems, memory allocations are automatically cleaned up on process exit. So it isn't really a leak if you allocate memory for objects that should exist for the lifetime of your process (e.g. the app delegate and anything it permanently holds on to) and rely on this behavior to free it on process exit.

Well... it's true that leaks can't detect all memory leaks, but let's say that you are doing this:
myIvarBrain=[self brain];
If you are giving it to an iVar (released in the dealloc of your class, and without accessors), actually there is no leak at all. The returned RC is one and it will be one since the deallocation of your class. If you don't release it in the dealloc, you should wait a dealloc of your class to see a memory leak.
Does make sense?

Related

Memory not fully freed

I just started creating an app using SceneKit and SpriteKit and ARC for the first time. I noticed that the memory usage is quickly increasing when I switch between different Views. My first thought was that I have memory leaks but I am not sure now. The behavior even occurs in this basic example:
for(int r=0;r<9999999;r+=1){
NSString *s=[NSString stringWithFormat:#"test%i",r];
s=nil;
}
From my understanding an NSString Object is created and directly released in this loop. I've tried this example in the iPhone-Simulator and on an iPhone and it makes the app use several hundreds MB of RAM after this loop is executed. (I am checking the memory usage with the Xcode debug navigator)
I am obviously misunderstanding something. Why is this example still retaining memory afterwards?
edit:
You could also create a new project: iOS -> Game -> Game Technology: SceneKit
Then add this into viewDidLoad:
for(int r=0;r<999999;r+=1){
SCNNode *tn=[SCNNode node];
tn=nil;
}
The memory will peak at 550MB and go down to 300MB which would be to much if there objects were fully released and removed from the RAM.
Don't rely on NSString for memory diagnostics. It has fairly atypical behavior.
This is a not-uncommon scenario, one that I've seen on S.O. more than once, that in an attempt to reduce some complicated memory problem to something simpler, the developer creates a simplified example using NSString, unaware that choosing that particular class introduces curious, unrelated behaviors. The new "Debug Memory Graph" tool or the old tried-and-true Instruments (discussed below) is the best way to diagnose the underlying issues in one's code.
As an aside, you talk about releasing objects immediately. If your method doesn't start with alloc, new, copy or mutableCopy, the object returned will not deallocated immediately after falling out of scope, because they're autorelease objects. They're not released until the autorelease pool is drained (e.g., you yield back to the run loop).
So, if your app's "high water" mark is too high, but memory eventually falls back to acceptable levels, then consider the choice of autorelease objects (and/or the introducing of your own autorelease pools). But generally this autorelease vs non-autorelease object distinction is somewhat academic unless you have a very long running loop in which you're allocating many objects prior to yielding back to the run loop.
In short, autorelease objects don't affect whether objects are deallocated or not, but merely when they are deallocated. I only mention this in response to the large for loop and the contention that objects should be deallocated immediately. The precise timing of the deallocation is impacted by the presence of autorelease objects.
Regarding your rapid memory increase in your app, it's likely to be completely unrelated to your example here. The way to diagnose this is to use Instruments (as described in WWDC 2013 Fixing Memory Issues). In short, choose "Product" - "Profile" and choose the "Leaks" tool (which will grab the essential "Allocations" tool, as well), exercise the app, and then look at precisely what was allocated and not released.
Also, Xcode 8's "Debug Object Graph" tool is incredibly useful, too, and is even easier to use. It is described in WWDC 2016's Visual Debugging with Xcode. With this tool you can see a list of objects in the left panel, and when you choose one, you can see the object graph associated with that object, so you can diagnose what unresolved references you might still have:
By the way, you might try simulating a memory warning. Cocoa objects do all sorts of caching, some of which is purged when there's memory pressure.
If you turned on any memory debugging options (e.g., zombies) on your scheme, be aware that those cause additional memory growth as it captures the associated debugging information. You might want to turn off any debugging options before analyzing leaked, abandoned or cached memory.
Bottom line, if you're seeing growth of a couple of kb per iteration and none of the objects that you instantiate are showing up and you don't have any debugging options turned on, then you might not need to worry about it. Many Cocoa objects are doing sundry cacheing that is outside of our control and it's usually negligible. But if memory is growing by mb or gb every iteration (and don't worry about the first iteration, but only subsequent ones), then that's something you really need to look at carefully.

Understanding Instruments and Memory Management

I'm in need of understanding how memory is managed in objective C.
I know the basics, if you create it and own it, you must release it yourself.
However, when it gets to code such as:
self.storeDict = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath2];
Do I own this? Must I release this memory?
self.storeDict = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath2];
//73.3% leak
totalCharacters = [storeDict count];
tagCounter = 1;
dictKeyArray = [[storeDict allKeys] mutableCopy];
//13.3% leak
When Instruments puts a bunch of percentages next to the highlighted leaks, what does that tell me? Does it tell me the size of the leak relative to the total amount of memory leaked?
And one last thing.. Is it normal for the amount of allocated memory to continuously rise? Or should it stabilize somewhere?
Thanks for all the help! Everything is greatly appreciated!
In most cases, you only own objects returned by methods whose names begin with "alloc", "new", "copy", or "mutableCopy". Of course, you also own anything to which you send -retain. Exceptions to these rules should be called out in the documentation for the non-conforming methods.
See https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-SW1
Instruments attributes a leak to the line where the object was created. However, that's not necessarily the code which leaked the object. If the pointer to the object was passed to some other code and that code did not balance its retains and releases, then that code is responsible for the leak. Instruments can show you the history of retains and releases for a specific object, and you'll have to review those to see which code is not discharging its ownership responsibilities properly.
Also, if an object is owned by another object and it's really that second object that was leaked, then everything it owned will have leaked "transitively" as it were. So, look for higher-level objects which have leaked before trying to track down low-level objects which have leaked. Often, it is the objects which have leaked fewer instances which are the root of a graph of leaked objects.
Whether it is normal for memory to keep rising or to stabilize, that depends a little. Usually, memory usage should stabilize. However, if your app really is doing more and more, then it may be normal for its memory usage to keep increasing. For example, if an app is receiving data over the network and accumulating results as it does so, then its memory usage would likely rise as more data arrives. But if it doesn't stop at some reasonable point, that's a problem. On an iOS device, the system will eventually kill it.

ARC reference counting dealloc, and release

I am getting a bit confused. I am creating an app with storyboard, and running it on iPad 1. the application uses a lot of memory, so reached the 120mb, crashes. accordingly to what I have understood to remove this problem you need to release, dealloc... the point is that with ARC this should be automatic. In fact if I add for e.g.: [label1 release]; it gives me an error. But this ARC automatic release and dealloc does not seem to work! Is this because there are different ways to release with ARC??
You don't need to manually retain/release/autorelease with ARC. However if you have active references to a lot of unused objects they will still remain in memory. Profile your app with Instruments and it will show you how many objects you're creating of each class and how much memory they're consuming.
With ARC you still need to think about memory usage you just don't need to worry as much about memory leaks.
NSObject *bigMemObj = [[BigMemClass alloc] init];
//This creates the object in memory. In both arc and manual counting the retain count is 1
//Do stuff
//Prior to ARC you would have had to call [bigMemObj release]; before setting the variable to nil
bigMemObj = nil
//With ARC you don't have to do anything. The compiler inserts the release at compile time
Also read the documentation on declaring iVars __strong vs __weak.
Without looking at your code it's hard to identify what is consuming all the memory but hopefully that should help you determine where to start looking.
You should implement #autoreleasePool{} inside each method. In essence, each method will look like the following:
-(void)methodName{
#autoreleasePool{
//do method stuff
}
}
This will ensure that, upon exiting the autoreleasePool, memory is properly released.
I can't vote this back up, otherwise I would. I think Alessandro is asking about ARC vs using release and dealloc, not about what he's loading!
So, Alessandro, your understanding is correct that with ARC you don't release or dealloc. Therefore, those won't work if you're using ARC. Also, there is no alternative to release/dealloc, since ARC doesn't use it.
My suggestion would be to look at what you're using in the app that is taking up all this memory. Do you have a large number of pictures, for example, that are very large? Keep any graphics as small as possible, matching the resolution of the iPad. Especially the iPad 1, which doesn't have the "retina display".
You can use Autorelease pools in ARC. Here is some documentation on when to use them:
NSAutoreleasePool Class Reference
Advanced Memory Management Programming Guide: About Memory Management

Does Objective-C have garbage collector on the iPhone?

I'm thinking of writing an app for the iphone. But I'm confused in regards to the objective-c language. Am I correct in saying that I have to do my own memory management? Is Objective-C a managed language such as C# and/or Java?
Thank you!
"Managed" is a marketing term that has no technical meaning. Objective C for the iPhone is not garbage collected, but uses retain counting memory management. So in some sense, you have to do your own memory management, but it's limited to knowing the Cocoa retain counting methodology.
Edit: My comments on "managed" refer to a previous post version. The comment is left here because I'm tired of seeing the word.
There is no garbage collection feature. However, any object you copy, retain, alloc etc. has its retain count bumped up by one, and you are responsible for calling a releaseor an autorelease - you own an instance of that object. If you don't call [<YOUROBJECT> release]; or [<YOUROBJECT> autorelease];, the object remains in the iPhone's/iPod Touch's/iPad's memory, but the pointer no longer remains, and a memory leak occurs, as that bit of memory can no longer be accessed. Autoreleasing adds the object to the autorelease pool, and means that it will become released at some point in the future. Always use a standard release where possible, as autorelease means that it will still stay in the device's memory for a while, you can never be sure when it will be released, and it is a slightly more demanding method to call.
Never call dealloc on an object - releasing or autoreleasing is sufficient, and if required, the object will automatically be dealloced.
Make sure you never release objects you do not own, and if you do release objects, you release them after you no longer have any use of them - otherwise, you may try to access that object, and the device cannot find the object, and the situation results in your app crashing due to an EXEC_BAC_ACCESS error - to find out the root of the problem, open Instruments, add the Object Allocation instrument and enable NSZombie detection in its preferences (or add the Zombies instrument (only available in iPhone SDK 3.2+)). You can then view the entire history of the object which causes the problem, and jump to the exact line of code that caused the problem.
You can read more here.
Hope this helped
As others have pointed out Objective-C has no garbage collector on the iPhone, but it does have one for Mac OSX. Here is an article describing this in more detail: http://vasudevkamath.blogspot.com/2010/01/objective-c-my-opinions.html
You have to do your own memory management with Objective-C on the iPhone.
The answer isn't specific to Objective-C. If you're doing iPhone development, no...there is no garbage collector. If you're developing for Mac OSX, however, there is garbage collection.

Track all Objective-C's alloc/allocWithZone/dealloc

Sorry for long description, however the questions aren't so easy...
My project written without GC. Recently I found a memory leak that I can't find. I did use new Xcode Analyzer without a result. I did read my code line by line and verified all alloc/release/copy/autorelease/mutableCopy/retain and pools... - still nothing.
Preamble: Standard Instruments and Omni Leak Checker don't work for me by some reason (Omin Tool rejects my app, Instruments.app (Leaks) eats too many memory and CPU so I have no chance to use it).
So I wanna write and use my own code to hook & track "all" alloc/allocWithZone:/dealloc messages statistics to write some simple own leaks checking library (the main goal is only to mark objects' class names with possible leaks).
The main hooking technique that I use:
Method originalAllocWithZone = class_getClassMethod([NSObject class],#selector(allocWithZone:));
if (originalAllocWithZone)
{
imp_azo = (t_impAZOriginal)method_getImplementation(originalAllocWithZone);
if (imp_azo)
{
Method hookedAllocWithZone = class_getClassMethod([NSObject class],#selector(hookedAllocWithZone:));
if (hookedAllocWithZone)
{
method_setImplementation(originalAllocWithZone,method_getImplementation(hookedAllocWithZone));
fprintf(stderr,"Leaks Hook: allocWithZone: ; Installed\n");
}
}
}
code like this for hook the alloc method, and dealloc as NSObject category method.
I save IMP for previous methods implementation then register & calculate all alloc/allocWithZone: calls as increment (+1) stat-array NSInteger values, and dealloc calls as decrement (-1).
As end point I call previous implementation and return value.
In concept all works just fine.
If it needs, I can even detect when class are part of class cluster (like NSString, NSPathStore2; NSDate, __NSCFDate)... via some normalize-function (but it doesn't matter for the issues described bellow).
However this technique has some issues:
Not all classes can be caught, for
example, [NSDate date] doesn't catch
in alloc/allocWithZone: at all, however, I can see alloc call in GDB
Since I'm trying to use auto singleton detection technique (based on retainCount readind) to auto exclude some objects from final statistics, NSLocale creation freezes on pre-init stage when starting of full Cocoa application (actually, even simple Objective-C command line utility with the Foundation framework included has some additional initialization before main()) - by GDB there is allocWithZone: calls one after other,....
Full Concept-Project draft sources uploaded here: http://unclemif.com/external/DILeak.zip (3.5 Kb)
Run make from Terminal.app to compile it, run ./concept to show it in action.
The 1st Question: Why I can't catch all object allocations by hooking alloc & allocWithZone: methods?
The 2nd Question: Why hooked allocWithZone: freezes in CFGetRetainCount (or [inst retainCount]) for some classes...
Holy re-inventing the wheel, batman!
You are making this way harder than it needs to be. There is absolutely no need whatsoever to roll your own object tracking tools (though it is an interesting mental exercise).
Because you are using GC, the tools for tracking allocations and identifying leaks are all very mature.
Under GC, a leak will take one of two forms; either there will be a strong reference to the object that should long ago been destroyed or the object has been CFRetain'd without a balancing CFRelease.
The collector is quite adept at figuring out why any given object is remaining beyond its welcome.
Thus, you need to find some set of objects that are sticking around too long. Any object will do. Once you have the address of said object, you can use the Object Graph instrument in Instruments to figure out why it is sticking around; figure out what is still referring to it or where it was retained.
Or, from gdb, use info gc-roots 0xaddr to find all of the various things that are rooting the object. If you turn on malloc history (see the malloc man page), you can get the allocation histories of the objects that are holding the reference.
Oh, without GC, huh...
You are still left with a plethora of tools and no need to re-invent the wheel.
The leaks command line tool will often give you some good clues. Turn on MallocStackLoggingNoCompact to be able to use malloc_history (another command line tool).
Or use the ObjectAlloc instrument.
In any case, you need to identify an object or two that is being leaked. With that, you can figure out what is hanging on to it. In non-GC, that is entirely a case of figuring out why it there is a retain not balanced by a release.
Even without the Leaks instrument, Instruments can still help you.
Start with the Leaks template, then delete the Leaks instrument from it (since you say it uses too much memory). ObjectAlloc alone will tell you all of your objects' allocations and deallocations, and (with an option turned on, which it is by default in the Leaks template) all of their retentions and releases as well.
You can set the ObjectAlloc instrument to only show you objects that still exist; if you bring the application to the point where no objects (or no objects of a certain class) should exist, and such objects do still exist, then you have a leak. You can then drill down to find the cause of the leak.
This video may help.
Start from the Xcode templates. Don't try to roll your own main() routine for a cocoa app until you know what you're doing.