Finding the cause of memory leak in Instruments - ios

I have run the leaks in Instruments and it is showing me a memory leak with a 100% value. I am able to see the line of code that is causing the problem. But not really sure what the error is..
- (void) listAllBooks {
if (marrListFromDB != nil) {
[marrListFromDB removeAllObjects];
marrListFromDB = nil;
}
marrListFromDB = [[NSMutableArray alloc] init];
ServerCommunicationAPI *servApi = [[ServerCommunicationAPI alloc] init];
servApi.delegate = self;
NSURL *url = [NSURL URLWithString:kLISTCONTENTS];
[servApi listBooksWithDeviceID:singleton.g_strdevID deviceKey:singleton.g_strdevID andSessionString:singleton.g_strSessionID sessionKey:#"sessionKey" URL:url andRequestMethod:#"POST"];
}
The line of error is the last one. Not sure why it is causing a memory leak... Need some guidance..

It is hard to tell from the information provided, but maybe the delegate property of ServerCommunicationAPI is declared as (strong)? In this case servApi could never be released, because it keeps a strong reference to itself (retain cycle).
I suggest that you check in instruments which kind of object leaks, this would make the answer much easier.

Try out this. May it resolve your memory leak problem.
- (void) listAllBooks {
if (marrListFromDB != nil) {
[marrListFromDB removeAllObjects];
marrListFromDB = nil;
}
ServerCommunicationAPI *servApi ;
marrListFromDB = [[NSMutableArray alloc] init];
if(servApi == nil){
ServerCommunicationAPI *servApi = [[ServerCommunicationAPI alloc] init];
}//Every time it going to alloc. It's strong object may be due do this memory leak happens.
servApi.delegate = self;
NSURL *url = [NSURL URLWithString:kLISTCONTENTS];
[servApi listBooksWithDeviceID:singleton.g_strdevID deviceKey:singleton.g_strdevID andSessionString:singleton.g_strSessionID sessionKey:#"sessionKey" URL:url andRequestMethod:#"POST"];
}

Just another idea: Maybe you execute your code in a separate thread for which no autorelease pool has been set up? In this case the message sent to servApi could create autorelease objects that cannot be released later since no autorelease pool exists.
So, if your code is not executed in the main thread, please check if an autorelease pool has been set up using a #autoreleasepool {...} block for your thread.

Related

How to release memory of global variables?

I want to release all the memory of global variables after I log out. Because, after I log out, the memory doesn't go down. I'm using ARC.
I've tried this code, but it doesn't work.
global.arrayStatus = nil;
global.arrayEmpName = nil;
global.arrayEmpNo = nil;
global.arrayDateTime = nil;
global.arraUpdatedBy = nil;
global.arrayDatePosted = nil;
global.arrayPostStatus = nil;
[self dismissViewControllerAnimated:YES completion:nil];
How large are the objects you are clearing? It could be that they are so small you're not noticing any visible memory change.
Check out Apple's guide on the Instruments tool, specifically the leaks section
Note that you may also have a retain cycle, which would avoid memory being purged and would also not show up in instruments
On a side note, if you are clearing all properties of your global object, then perhaps it could be easier just replacing it with a new instance, rather than clearing each of its properties.
// Beats writing more than one line
global = [[GlobalObject alloc] init];
[self dismissViewControllerAnimated:YES completion:nil];
Remember to not use super delloc in arc
-(void)dealloc{
global.arrayStatus = nil;
global.arrayEmpName = nil;
global.arrayEmpNo = nil;
global.arrayDateTime = nil;
global.arraUpdatedBy = nil;
global.arrayDatePosted = nil;
global.arrayPostStatus = nil;
}

Memory Leak using ASIHTTPRequest appendPostData with ARC

I've been having a memory leak in a upload speedtest function that has been recently converted to ARC. I believe I've adhered to the memory management guidelines for ARC.
The issue seems to be with the chuck of random data I create for the upload test. Its memory doesn't seem to get freed.
Here is where I create the upload data and ASIHTTPRequest object:
ASIHTTPRequest *request0 = [ASIHTTPRequest requestWithURL:uploadTestURL];
__weak ASIHTTPRequest *request = request0;
NSData *uploadData ;
if ([speedTier isEqualToString:#"Wifi"]) {
uploadData = [self createRandomNSDataOfSize:1000000];
}else
{
uploadData = [self createRandomNSDataOfSize:4000000];
}
[request appendPostData:uploadData];
The function that actually creates the data is:
NSMutableData* theData = [NSMutableData dataWithCapacity:size];
for( unsigned int i = 0 ; i < size/4 ; ++i )
{
u_int32_t randomBits = arc4random();
[theData appendBytes:(void*)&randomBits length:4];
}
return theData;
I then proceed to set up the block for setBytesSentBlock, where I manage the graphics for the upload and moment of termination of upload. Some of the code is below:
[request0 setBytesSentBlock:^(unsigned long long size, unsigned long long total) {
double timeDiffereceFromStart = [[NSDate date] timeIntervalSinceDate:start];
if (totalUploadSize == 0)
{
start=[NSDate date];
totalUploadSize = [request.postBody length];
return;
}
if(startPosition == 0 && timeDiffereceFromStart >= 1)//[request totalBytesSent] > 20000)
{
startPosition = [request totalBytesSent];
start=[NSDate date];
return;
}
I've just posted some of the code, but wanted to show where I used the variable 'request' within the block. I'm pretty sure I've fixed the circular retain issue here, but I wanted to make sure there wasn't some other problem.
On other thing I should note - I've put a break point within the ASIHTTPRequest dealloc function. All of the objects of this type that I create hit the dealloc breakpoint. So they are all being freed properly. But I don't understand why the memory usage keeps going up when it hits the upload function.
Thanks!
I've figured out the issue, and it was a retain cycle which involved the parent class of the class from which I posted the code. Because this part of the system isn't wasn't written by me, I missed it. I ended up fixing the warnings that point out retain cycles when using blocks, and the memory leaks were gone.

Leak when using blocks, collections and ARC

I'm trying to understand why this code is leaking, using ARC:
- (IBAction)block2:(id)sender {
NSMutableString *aString = [[NSMutableString alloc] init];
void (^aBlock)() = ^{
NSMutableString __unused *anotherString = aString;
};
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObject:aBlock forKey:#"Key"];
}
As you can see, I put a block inside a collection (NSMutableDictionary, but it's the same if I use NSDictionary, NSArray ecc...), then the method returns and the dictionary is deallocated. The block should then be released. But, using instruments, I see a leak
"just to be sure" that the block has no other references, I added this line at the end of the method:
[dict setObject:[NSNull null] forKey:#"Key"];
same result.
I've found this post but the answers point to another problem:
Blocks inside NSMutableArray leaking (ARC)
Then, this is the magic:
If I change this line:
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObject:aBlock forKey:#"Key"];
to:
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObject:[aBlock copy] forKey:#"Key"];
the leak disappear.
I know that, under non-ARC, before passing a reference of a block literal, I must copy it (when declared literal, it's on the stack, so I need to copy it to the heap before passing outside the scope of the function where is declared)...but using ARC I shouldn't care about it.
Any indication?
This is happening with all versions from 5.0 to 6.1.
EDIT: I've made some tests, trying to understand if I'm doing something wrong or if there is some bug...
First: Am I reading wrong instruments informations?
I don't think, the leak is real and not my mistake. Look at this image...after executing the method 20 times:
Second: what happens if I try to do the same thing in a non arc environment?
this adds some strange behavior:
same function in NON-ARC environment:
- (IBAction)block2:(id)sender {
NSMutableString *aString = [[NSMutableString alloc] init];
void (^aBlock)() = ^{
NSMutableString __unused *anotherString = aString;
};
[aString release];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObject:[[aBlock copy] autorelease] forKey:#"Key"];
}
With the previous non-arc implementation, I have a leak only for the block (not for the string)
Changing the implementation to use an autorelease on the mutable string declaring solves the leak!!! I can't understand why, and I'm not sure if it could be related to the main post issue
// version without leak
- (IBAction)block2:(id)sender {
NSMutableString *aString = [[[NSMutableString alloc] init] autorelease];
void (^aBlock)() = ^{
NSMutableString __unused *anotherString = aString;
};
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObject:[[aBlock copy] autorelease] forKey:#"Key"];
}
CONCLUSIONS:
After various answers and further investigating, I understood some things:
1- Apple docs says that you must use [^{} copy] when you pass a block to a collection. This is because ARC doesn't add the copy itself. If you don't, the collection (array, dictionary..) sends a retain on a STACK ALLOCATED OBJECT - which does nothing. When the method ends, the block goes out of scope and becomes invalid. You will probably receive a bad access when using it. But note: this is not my case, I'm experiencing a different problem
2- the problem I'm experiencing is different: the block is over-retained (the opposite problem --> the block is still alive even when it shoulnd't be). Why?
I've found this: in my example, I'm using this code
void (^aBlock)() = ^{
NSMutableString __unused *anotherString = aString;
};
this code, under NON-ARC, stores a reference (aBlock) to the literal block. The block is allocated on the stack, so if you NSLog(#"%p", aBlock) -> you will see a stack memory address
But, this is the "strange" (I don't find any indication in Apple docs), if you use the same code under ARC and NSLog aBlock address, you will see that now it's on the HEAP!
For this reason the behavior is different (no bad access)
So, both incorrect but different behavior:
// this causes a leak
- (IBAction)block2:(id)sender {
NSMutableString *aString = [[NSMutableString alloc] init];
void (^aBlock)() = ^{
NSMutableString __unused *anotherString = aString;
};
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObject:aBlock forKey:#"Key"];
}
// this would cause a bad access trying to retrieve the block from the returned dictionary
- (NSMutableDictionary *)block2:(id)sender {
NSMutableString *aString = [[NSMutableString alloc] init];
return [NSMutableDictionary dictionaryWithObject:^{
NSMutableString __unused *anotherString = aString;
} forKey:#"Key"];
}
3 - about my last test under NON-ARC, I think that the release is in the wrong place. I released the string before adding the block to the dictionary with copy-autorelease.
The block automatically retains the variables referenced inside the block, but the retain message is sent at the copy moment, not at the declaration. So, If I release aString before copying the block, it's retain count goes to 0, then the block sends a retain message to the "zombie" object (with unexpected behavior, it can leak the block, crash, ecc ecc)
See this question for reference iOS 5 Blocks ARC bridged cast; it demonstrates the nightmare that are Blocks and ARC.
Typically, if you assign a block to a variable that lives beyond your current scope, the compiler will be automatically able to copy the block to the heap. This means when you fall out of scope, you still have the block hanging around. Similarly, the same goes with block paramaters. The compiler is aware that it'll need to make a copy of those parameters, and hence does so.
The issue with classes such as NSArray is that they don't usually need to copy an object to keep it correctly; typically they only retain the object. Whereas an object going out of scope is part of the language (hence it copies), keeping it within an object like NSArray is an application level operation. As such, the compiler isn't clever enough yet to determine that the block needs copying (Blocks are standard Obj-C objects after all, it thinks all it needs to do is retain it). In a similar vain, thats why any properties that hold blocks need to specify the copy keyword. The automatic synthesis of the property methods aren't aware a block is being stored, and need to be given a nudge to copy them when being set.
This demonstrates why the whole thing works when you use - copy on your block, you're doing what the compiler should be doing, but is not clever enough to do so...Apple even recommends this technique within its Transitioning to ARC documentation, see the FAQs.
Bootnote: In case you're wondering why I'm on about retaining, even when you're using ARC, is that this is what ARC does under the hood. The memory management model is still the same as before, but the onus is now on the system to manage it for us based on naming and conventions, whereas previously the onus was on the developer to manage their memory correctly. It's just that for blocks, the system isn't able to manage it as fully as it should, and hence the developer needs to step in from time to time.
Blocks begin their life on the stack for performance reasons. If they should live longer than the stack is around, they have to be copied to the heap.
In MRR, you had to do that copying yourself. ARC is doing that automatically for you if you pass a block up the stack (i.e. return it from a method). But if pass a block down the stack (for example, store it in an NSMutableDictionary or NSMutableArray), you have to copy it yourself.
This is documented in Apple's Transitioning to ARC documentation, search for "How do blocks work in ARC" inside that document.
For your Non-ARC examples (as you wrote in your conclusion), the copy of the block should happen before releasing aString, as aString is retained when the block is copied. Otherwise your code will show undefined behavior, it may even crash. Here is some code that demonstrates the problem with Non-ARC:
NSObject *object = [[NSObject alloc] init];
void (^aBlock)() = ^{
NSLog(#"%#", object);
};
[object release];
aBlock(); // undefined behavior. Crashes on my iPhone.

Issue with allocating object and releasing ios

I have a memory leak with below code.
Where self.firstURLConn is #property(nonatomic, retain).
NSMutableURLRequest* req = [[NSMutableURLRequest alloc] initWithURL:urlcachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:60.0f];
self.firstURLConn = [[[NSURLConnection alloc] initWithRequest:req delegate:self] autorelease];
[req release];//memory leak here and with self.firstURLConn
Why memory is leaking here
Did you ever run Product > Analyze yet? If you did please show us the memory leaking issue log.
They will not only tell the line of your code that have memory leak issue but show the step of your code that cause the problem.
I suggest you to use Instrument tool with leaking tool. It will show the in-depth information about your code problem.
EDIT: req variable miss autorelease. because of req has been retain 2 time. change the code like this
NSMutableURLRequest* req = [[[NSMutableURLRequest alloc] initWithURL:urlcachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:60.0f] autorelease];
self.firstURLConn = [[[NSURLConnection alloc] initWithRequest:req delegate:self] autorelease];
[req release];//memory leak here and with self.firstURLConn
Because of your firstURLConn has declared in retain properties. So,the dealloc method, you should set nil to this properties
- (void)dealloc
{
self.firstURLConn = nil;
[super dealloc];
}
firstURLConn will retain your req, req will be only deallocated when firstURLConn will release req.
Since the delegate method returns asynchronously (sometime in the future) you must release the NSURLConnection inside of the delegate method. Remove the autorelease and add a release in the completed and failed delegate methods.

iPhone memory management problems

I detach a thread calling my method which has a while-loop. Even though I have them marked as autoreleasepool, I release the objects manually, since the while-loop can continue on for a some time.
The problem is that after a while, the app crashes due to memory problems. If I look in Instruments, I can see a huge pile of NSStrings allocated and a stairway to heaven is created in the graph. What have I failed to release?
while (keepGettingScores)
{
NSString *jsonString = [[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
NSDictionary *json = [jsonString JSONValue];
[jsonString release];
NSMutableArray *scores = [[NSMutableArray alloc] init];
[scores setArray:(NSMutableArray*)[[jsonString JSONValue] objectForKey:#"scores"]];
NSSortDescriptor *sorter = [[NSSortDescriptor alloc] initWithKey:#"totalScore" ascending:NO];
[scores sortUsingDescriptors:[NSArray arrayWithObject:sorter]];
[sorter release];
[self performSelectorOnMainThread:#selector(updatePlayerTable:) withObject:scores waitUntilDone:NO];
[scores release];
[NSThread sleepForTimeInterval:1.0];
}
I don't see anything glaring, could there be an issue under the hood in your JSON library?
Are you draining your pool after your thread is finished executing?
You need to create an NSAutoreleasePool and call its drain method when your thread is finished executing.
In one of my projects, I had a thread that needed to create a lot of autorelease objects and found it useful to periodically drain the pool as the thread was running.
- (void)doStuff:(NSObject *)parent {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
/* Do lots of stuff *.
/* Periodically, I'd drain and recreate the pool */
[pool drain];
pool = [[NSAutoreleasePool alloc] init];
/* The rest of my stuff */
[pool drain];
}
And doStuff: is called using detachNewThreadSelector:
ok some BIG problems i see is
1
this..
[self performSelectorOnMainThread:#selector(updatePlayerTable:) withObject:scores waitUntilDone:NO];
is passing scores which could be getting retained by something else and that would also retain all the objects it contains.
2
scores is a nsmutablearray and is explicitly defined as NOT THREAD SAFE yet you are passing it across threads.
3
those [blah JSONvalue] things should be autoreleased and that is not apple api, apple has no public JSON api for iphone. that is most likely SBJSON library which puts categories on apple classes(nsstring, nsarray, nsdictionary, etc) for convenient JSON parsing.

Resources