I am getting a memory leak on the following code line:
The code-line:
NSArray *fetchedObjects = [qContext executeFetchRequest:fetchRequest error:&error];
I have been trying to read-up on this and have tried to find the cause of this for quite some time, without success.
Could someone give me a hint where to look? ...and do i understand the "100%" correctly that it indicate that this code line is 100% causing the leak?
UPDATE
Some more code:
//=========PREPARE CORE DATA DB===========//
if (managedObjectContext == nil) { managedObjectContext = [(FamQuiz_R0_1AppDelegate *)
[[UIApplication sharedApplication] delegate] managedObjectContext]; }
// Define qContext
NSManagedObjectContext *qContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"questions" inManagedObjectContext:qContext];
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [qContext executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject *info in fetchedObjects) {
if ([[info valueForKey:#"qDiff"] intValue] == 1) {
[allEasyArrayQ addObject:[info valueForKey:#"idQ"]];
} else if ([[info valueForKey:#"qDiff"] intValue] == 2) {
[allMediumArrayQ addObject:[info valueForKey:#"idQ"]];
} else if ([[info valueForKey:#"qDiff"] intValue] == 3) {
[allHardArrayQ addObject:[info valueForKey:#"idQ"]];
}
}
You are probably over-retaining the array or the objects inside it later in this method or even outside of this method. The line will only indicate where the objects are created, not where the actual extra retain is performed. For that you'd need to check using Instruments which call stacks retain and release the leaked objects.
No, the 100% means that this leak accounts for 100% of your leaked memory (ie, this is you only leak).
Note if you want to fix the leak you are looking in the wrong place. Leaks tells you which instance is leaking, it's Class and it's memory management history. Try a tutorial like this one http://www.cimgf.com/2008/04/02/cocoa-tutorial-fixing-memory-leaks-with-instruments/
Note, what Leaks can't tell you is the line where you are leaking, as the cause of your leak is something you haven't done, as opposed to something you have done (ie you didn't release your object).
Related
I want to deal with a data attribute, named originalImage in every Media entity in the store.
The problem is that despite the autoreleasing, memory builds up every time it's accessed via valueForKey, and eventually the app crashes. Or perhaps it's loading large individual NSData items which is the problem, but Instruments shows it to be a steadily inclining graph of memory usage, until it eventually gives me a memory warning and then crashes.
I haven't started on the rest of the code for this yet, so i'm not performing some hidden task that i'm not showing you.
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Media"
inManagedObjectContext:[self managedObjectContext]];
[request setEntity:entity];
[request setFetchBatchSize:10];
NSArray *mediaItems = [[self managedObjectContext] executeFetchRequest:request error:nil];
for (NSManagedObject *media in mediaItems) {
#autoreleasepool {
[media valueForKey:#"originalImage"];
}
}
EDIT: Today it seems that even just mentioning the NSManagedObject media is enough to cause this media leak. So even without the valueForKey line, i have a leak. I've tried this:
while (i < count) {
#autoreleasepool {
NSManagedObject *media = [mediaItems objectAtIndex:i];
[[self managedObjectContext] refreshObject:media mergeChanges:NO];
NSLog(#"i: %i", i);
i++;
}
}
This also didn't work, and crashed at the same point.
Did you try something like:
for(int i=0;i<[mediaItems count]; i++) {
#autoreleasepool {
NSManagedObject *media = [mediaItems objectAtIndex:i];
[media valueForKey:#"originalImage"];
}
}
Maybe this way "media" gets released properly at every loop.
(Sorry, I put this on a comment. I'm new on SO and not enough rep.)
I want to insert 200 5Mb records in my Core Database. But when I save the NSManagedObject, the memory wasn't released (autoreleased pool didn't help), and after inserting 30 records I got the memory warning and the application crashed. Here is my code
- (void)SaveItem
{
NSString *entityName = kEntityName;
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = appDelegate.managedObjectContext;
NSEntityDescription *entityDesctiption = [NSEntityDescription
entityForName: entityName
inManagedObjectContext:context];
// check if town exists
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"id == %d", self.imageID];
NSFetchRequest *requestToCheckExistense = [[NSFetchRequest alloc] init];
[requestToCheckExistense setEntity:entityDesctiption];
[requestToCheckExistense setPredicate:predicate];
NSArray *objects = [context executeFetchRequest:requestToCheckExistense error:nil];
[requestToCheckExistense release];
if (objects == nil)
{
NSLog(#"there was an error");
}
NSManagedObject *object;
if ([objects count] > 0)
{
// edit item
object = [objects objectAtIndex:0];
}
else
{
// if object doesn't exist, find max id to imlement autoincrement
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesctiption];
request.propertiesToFetch = [NSArray arrayWithObjects: #"id", nil];
NSArray *allobjects = [context executeFetchRequest:request error:nil];
[request release];
NSInteger newID = 1;
if ([allobjects count] > 0)
{
NSNumber *maxID = [allobjects valueForKeyPath:#"#max.id"];
newID = [maxID intValue] + 1;
}
// write item
object = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context];
[object setValue:[NSNumber numberWithInt:newID] forKey:#"id"];
self.imageID = newID;
}
// fill NSManagedObject
// size of objNSData is about 5MB
NSMutableData *objNSData = [[DatabaseManager sharedDatabaseManager] encryptedDataFromImage:bigImage];
[object setValue:objNSData forKey:#"big"];
[context save:nil];
}
When I commented
[object setValue:objNSData forKey:#"big"];
everything was OK.
I tried to add the code into #autoreleasepool , but that didn't help.
I know, that now, when I save data to database, it's still in iPhone RAM. How to release it from this memory? When I get a set of Managed Objects from the database, they are not in the RAM (I can easyly get 100 object, each of them has 5Mb fields)
object =(tblEntity *) [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context];
try to type cast the object,this may solve the problem
I've solved the issue.
after call of [self SaveItem];
I used
[context save];
[context reset];
[context save];
all the NSManagedObjects from the context will be released.
After that operation I can add as many big objects as I want
Because you don't own an NSManagedObject when you create it, it may be retained by the core data stack even after releasing it (when using an autoreleasepool contained inside the loop).
This may help:
Set the undo manager of your managedobjectContext to nil:
[context setUndoManager:nil];
Be sure that no properties of that object are retained anywhere, because then the managed object will not be released on time inside your loop.
Be sure to add an autorelease pool inside every loop execution, not wrapping all the loop itself, similar to:
for(i;i<n;i++) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
[obj saveItem];
[pool drain];
}
If that object belongs to a hierarchy of NSManagedObjects, then you need to release the owner of this object too, for this one to be deallocated from memory.
You can check apple's documentation about memory management in CoreData.
Warning: big objects (> 1MB) are not recommended by Apple to be stored inside CoreData (Check this other question/answer.)
I am very new at this and seems to have a leak in this piece of code that i cannot fix:
The Instruments shows on this line with a 100%:
NSMutableArray *read_Question = [[NSMutableArray alloc] initWithCapacity: 0];
I have tried all kind of things but not been able to fix it.
Anyone nice that can advice me how to proceed?
- (NSMutableArray *)readQuestion: (int)questionNr {
NSMutableArray *read_Question = [[NSMutableArray alloc] initWithCapacity: 0];
NSError *error;
//=========PREPARE CORE DATA DB===========//
if (managedObjectContext == nil) {
managedObjectContext = [(FamQuiz_R0_1AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]; }
// Define qContext
NSManagedObjectContext *qContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"questions" inManagedObjectContext:qContext];
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [qContext executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject *info in fetchedObjects) {
if ([[info valueForKey:#"idQ"] intValue] == questionNr) {
[read_Question addObject:[info valueForKey:#"question"]];
[read_Question addObject:[info valueForKey:#"qRightAnswer"]];
[read_Question addObject:[info valueForKey:#"qWrongAnswer1"]];
[read_Question addObject:[info valueForKey:#"qWrongAnswer2"]];
}
}
[fetchRequest release];
return [read_Question autorelease];
}
It seams that you are returning the object only inside the if statement. Meaning that if the if statement is false you will not autorelease the array. Or maybe you didn't paste the entire method. Let me know. Instruments is sometimes tricky.
This is a dupe of your other question Memory leak problem and i need help #1
When i did release i got into trouble,
of course. I did try to change the
names on the three and do release so
there was unique names but that did
not work.
Changing the names across three different files? That won't do anything and it indicates that you haven't entirely wrapped your head around objects, pointers, and memory management.
The Objective-C and Memory Management guides will help.
Could this be the reason for the leak
i have in this .m file?
Nope -- as I answered in the other question, the leak is most likely because you retain the object that is returned by that method and then don't release it anywhere.
Instruments is telling you were the leaked object was allocated, not where it was necessarily leaked.
While you may not be autoreleasing the array in all cases on return from that method, you might also be retaining it somewhere else and not balancing that retain with a release.
I am assuming you set the property managedObjectContext to "retain". Change the line to this (include "self" so that it gets retained):
if (self.managedObjectContext == nil) { self.managedObjectContext = [(FamQuiz_R0_1AppDelegate *)
[[UIApplication sharedApplication] delegate] managedObjectContext]; }
Then add your release back in.
Since I believe the code from picciano will fix the issue of the openingsposter, here a small explanation why it should fix the issue.
If you give a property the retain attribute, it will create an accessor method that looks somewhat like this (simplified):
#property (nonatomic, retain) NSValue *value;
- (void)setValue:(NSValue *)aValue {
value = [aValue retain];
}
Only when the retainCount reaches 0 an object is released, using retain, alloc and copy increases the retainCount. Remember: only when using the accessor method the retain actually happens (besides using alloc, retain and copy directly). The accessor method is usually called when using one of the following methods:
// the 2 most obvious ways to call the accessor methods ...
object.value = someValue;
[object setValue:someValue];
You created a retain property in your code, yet you didn't use the accessor method, so the object was never retained.
// no accessor used here ...
managedObjectContext = [(FamQuiz_R0_1AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
If you would release it from this point on, it would cause a crash, since the retainCount would actually become -1 at some point (since it never got to 1 in the first place). Therefore you should set the property like this:
// the dot-notation syntax to make use of the accessor method ...
self.managedObjectContext = [(FamQuiz_R0_1AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
or (in my opinion preferably):
// making use of the accessor method directly, which is very unambiguous ...
NSManagedObjectContext *context = [(FamQuiz_R0_1AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
[self setManagedObjectContext:context];
This way you can be sure the retain actually happens.
The second notation to accessor setters is in my opinion superior and I consider it good habit to use it for setting properties whenever possible. Read more about people who share this opinion and their reasoning on the following sites:
Cocoa Is My Girlfriend
The Big Nerd Ranch
I am very new at this and seems to have a leak in this piece of code that i cannot fix:
The Instruments shows on this line with a 100%:
NSMutableArray *read_Question = [[NSMutableArray alloc] initWithCapacity: 0];
I have tried all kind of things but not been able to fix it.
Anyone nice that can advice me how to proceed?
- (NSMutableArray *)readQuestion: (int)questionNr {
NSMutableArray *read_Question = [[NSMutableArray alloc] initWithCapacity: 0];
NSError *error;
//=========PREPARE CORE DATA DB===========//
if (managedObjectContext == nil) {
managedObjectContext = [(FamQuiz_R0_1AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]; }
// Define qContext
NSManagedObjectContext *qContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"questions" inManagedObjectContext:qContext];
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [qContext executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject *info in fetchedObjects) {
if ([[info valueForKey:#"idQ"] intValue] == questionNr) {
[read_Question addObject:[info valueForKey:#"question"]];
[read_Question addObject:[info valueForKey:#"qRightAnswer"]];
[read_Question addObject:[info valueForKey:#"qWrongAnswer1"]];
[read_Question addObject:[info valueForKey:#"qWrongAnswer2"]];
}
}
[fetchRequest release];
return [read_Question autorelease];
}
It seams that you are returning the object only inside the if statement. Meaning that if the if statement is false you will not autorelease the array. Or maybe you didn't paste the entire method. Let me know. Instruments is sometimes tricky.
This is a dupe of your other question Memory leak problem and i need help #1
When i did release i got into trouble,
of course. I did try to change the
names on the three and do release so
there was unique names but that did
not work.
Changing the names across three different files? That won't do anything and it indicates that you haven't entirely wrapped your head around objects, pointers, and memory management.
The Objective-C and Memory Management guides will help.
Could this be the reason for the leak
i have in this .m file?
Nope -- as I answered in the other question, the leak is most likely because you retain the object that is returned by that method and then don't release it anywhere.
Instruments is telling you were the leaked object was allocated, not where it was necessarily leaked.
While you may not be autoreleasing the array in all cases on return from that method, you might also be retaining it somewhere else and not balancing that retain with a release.
I am assuming you set the property managedObjectContext to "retain". Change the line to this (include "self" so that it gets retained):
if (self.managedObjectContext == nil) { self.managedObjectContext = [(FamQuiz_R0_1AppDelegate *)
[[UIApplication sharedApplication] delegate] managedObjectContext]; }
Then add your release back in.
Since I believe the code from picciano will fix the issue of the openingsposter, here a small explanation why it should fix the issue.
If you give a property the retain attribute, it will create an accessor method that looks somewhat like this (simplified):
#property (nonatomic, retain) NSValue *value;
- (void)setValue:(NSValue *)aValue {
value = [aValue retain];
}
Only when the retainCount reaches 0 an object is released, using retain, alloc and copy increases the retainCount. Remember: only when using the accessor method the retain actually happens (besides using alloc, retain and copy directly). The accessor method is usually called when using one of the following methods:
// the 2 most obvious ways to call the accessor methods ...
object.value = someValue;
[object setValue:someValue];
You created a retain property in your code, yet you didn't use the accessor method, so the object was never retained.
// no accessor used here ...
managedObjectContext = [(FamQuiz_R0_1AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
If you would release it from this point on, it would cause a crash, since the retainCount would actually become -1 at some point (since it never got to 1 in the first place). Therefore you should set the property like this:
// the dot-notation syntax to make use of the accessor method ...
self.managedObjectContext = [(FamQuiz_R0_1AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
or (in my opinion preferably):
// making use of the accessor method directly, which is very unambiguous ...
NSManagedObjectContext *context = [(FamQuiz_R0_1AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
[self setManagedObjectContext:context];
This way you can be sure the retain actually happens.
The second notation to accessor setters is in my opinion superior and I consider it good habit to use it for setting properties whenever possible. Read more about people who share this opinion and their reasoning on the following sites:
Cocoa Is My Girlfriend
The Big Nerd Ranch
I desperately need help with a memory leak in my iPhone app. The app is ready to submit to the app store, is stable, has no memory leaks at all in iPhone simulator or Clang ... but seems riddled with them on my iPod Touch.
They all seem to stem from managedObjectModel when I'm trying to retrieve data from Core Data.
The Core Data code in my app was automatically created by Xcode a while back, I've noticed that the code has since changed when you get xcode to generate it ... I've tried with the old and new but it makes no difference.
If I comment out the following code, the problem goes away ... can anyway see what's wrong with it? I've spent 9 hours on this so far and just can't figure it out!
NSString *entityForName = [[NSString alloc] initWithString:#"OfflineSettings"];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityForName inManagedObjectContext:[self managedObjectContext]];
[request setEntity:entity];
[entityForName release];
NSSortDescriptor *sortById = [[NSSortDescriptor alloc] initWithKey:#"Id" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObject:sortById]];
[sortById release];
NSError *error;
NSMutableArray *mutableFetchResults = [[[self managedObjectContext] executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil) {
// Handle the error.
NSLog(#"Error fetching");
}
int intId = -1;
if ([mutableFetchResults count] == 0) {
TTDERROR(#"No id has been saved to offline settings");
} else {
OfflineSettings *offlineSettings = (OfflineSettings *)[mutableFetchResults objectAtIndex:0];
intId = [offlineSettings.Id intValue];
}
[mutableFetchResults release];
[request release];
The leak specifically seems to be on this line:
NSMutableArray *mutableFetchResults = [[[self managedObjectContext] executeFetchRequest:request error:&error] mutableCopy];
.. and the code for [self managedObjectContext] is as follows in case it helps ..
- (NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext_ != nil) {
return managedObjectContext_;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext_ = [[NSManagedObjectContext alloc] init];
[managedObjectContext_ setPersistentStoreCoordinator:coordinator];
}
return managedObjectContext_;
}
I'm really at a loss, so I would be so grateful for some help!
Steven
You don't need the mutable copy. executeFetchRequest: returns an autoreleased static array and you're not mutating the array. (I keep seeing this. Must be in an example somewhere.) Likewise, creating the entityForName NSString is pointless. Just put the string literal in the entityForName: to eliminate another possible source of error.
Niether of these are the likely source of the leak but you should remove them anyway.
As a rule of thumb, if you have troubles on device but not simulator or on one hardware but not others, then the problem is in a library/framework that is not properly compiled for the hardware where the error occurs. There really isn't any type of coder error that leaks in one environment but not others. When we make a mistake, it's universal.
It's also possible for resources such as images and sounds to behave differently because different devices use different graphics and audio hardware. That, however, is rather rare.
If you run the code through Instruments it should tell you exactly what object is leaking.