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;
}
Related
I've started writing my first serious attempt at a hybrid, Cordova/Objective-C program for iOS, and I'm currently hitting some stumbling blocks regarding memory allocations. I need to get the user's Album art to display within the web view. I got the art to display successfully, but now there's a ton of memory being allocated.
Using the "Instruments" tool and comparing Generational Snapshots, I've narrowed my guilty culprits down to these methods - which I all wrote from scratch. But I'm confused - since I'm using automatic reference counting, and that I have everything in autorelease pools, that there shouldn't be any wasted memory. Funny thing is, I see no "leaks" being reported - just a heap that gets bigger, with more and more memory allocated.
I've attached some screenshots of the Instruments tool:
Here are direct links to the images since there is so much text:
http://i.imgur.com/rkc5dhA.png
http://i.imgur.com/U2esgBT.png
http://i.imgur.com/fmt3Mv4.png
Here's the contents of the "BukketHelper.M" class that I made (matches the header, no strong properties or any other definitions of any sort):
-(NSString *) convertULLToNSString:(NSNumber* )guid
{
return [NSString stringWithFormat:#"%llu", [guid unsignedLongLongValue]];
}
-(NSNumber *) convertStringToULL:(NSString *) guid
{
//get string to number
//this causes memory to not be released
unsigned long long ullvalue = strtoull([guid UTF8String], NULL, 10);
NSNumber *numberID = [[NSNumber alloc] initWithUnsignedLongLong:ullvalue];
return numberID;
}
Here's the contents of the "MediaQuery.M" class that I made (this matches the header exactly, no strong properties or other definitions):
-(MPMediaItem*) getMediaItemULL:(NSNumber*)guid
{
#autoreleasepool {
//run the query on
MPMediaQuery *query = [[MPMediaQuery alloc] init];
[query addFilterPredicate:[MPMediaPropertyPredicate predicateWithValue:guid forProperty:MPMediaItemPropertyPersistentID]];
//get and return the item
NSArray *mediaResults = [query items];
return [mediaResults firstObject];
}
}
-(MPMediaItem*) getMediaItem:(NSString*)guid
{
#autoreleasepool {
BukketHelper* bh = [[BukketHelper alloc] init];
return [self getMediaItemULL:[bh convertStringToULL:guid]];
}
}
-(UIImage*) getMediaAlbumArtAsUIImage:(NSString*)guid withQuality:(NSNumber*)quality withLength:(NSNumber*)length subsituteImageName:(NSString* )filename
{
return [self getMediaAlbumArtFromMediaItemAsUIImage:[self getMediaItem:guid] withQuality:quality withLength:length subsituteImageName:filename];
}
-(NSString*) getMediaAlbumArtAsBase64:(NSString*)guid withQuality:(NSNumber*)quality withLength:(NSNumber*)length subsituteImageName:(NSString* )filename
{
NSString *base64 = nil;
#autoreleasepool {
UIImage* rawImage = [self getMediaAlbumArtAsUIImage:guid withQuality:quality withLength:length subsituteImageName:filename];
NSData *imageData = nil;
if (rawImage != nil)
{
#autoreleasepool {
//this causes memory to not be released
imageData = UIImageJPEGRepresentation(rawImage, [quality floatValue]);
base64 = [imageData base64EncodedStringWithOptions:0];
}
}
}
return base64;
}
-(UIImage*) getMediaAlbumArtFromMediaItemAsUIImage:(MPMediaItem*)item withQuality:(NSNumber*)quality withLength:(NSNumber*)length subsituteImageName:(NSString* )filename
{
UIImage *rawImage = nil;
#autoreleasepool {
bool successfulArt = NO;
if (item != nil)
{
MPMediaItemArtwork *albumArt = [item valueForProperty:MPMediaItemPropertyArtwork];
if (albumArt != nil) {
#autoreleasepool {
//this causes memory to not be released
rawImage = [albumArt imageWithSize:CGSizeMake([length doubleValue], [length doubleValue])];
successfulArt = YES;
}
}
}
if (successfulArt == NO)
{
rawImage = [UIImage imageNamed:filename];
}
}
return rawImage;
}
So yeah - my question is: What am I doing wrong when it comes to memory allocation and leaks? My current tests are exclusively using album art - so "UIImage imageNamed" shouldn't be the issue (from it's caching). In addition, I've read that ARC cannot release CoreGraphics objects, which could also be the problem.
I really could use some help with this! Thank you!
I ran into the same problem. I think there's a bug in the framework which doesn't release the memory. Basically there's a huge spike in allocated memory each time func imageWithSize(size: CGSize) -> UIImage? is called.
If it helps you any, I noticed that if you call this function passing in the artwork.bounds.size (instead of creating a new image size each time) then the memory gets allocated only once and calling imageWithSize again (with the same dimensions) does not reallocate new memory. This appears to only be true if you pass in the size of the original artwork image and don't return a custom size. If you need a custom size, perhaps you can then resize the UIImage on your own and not rely on this buggy method.
For the purpose of ensuring I have chosen the correct NSMergePolicy I am curious as to whether a value being set to its current value is capable of causing a merge conflict across multiple contexts.
Specifically, in my case I want to ensure that a modified flag will conflict and be preserved if set at an inopportune moment.
Example:
//...
//on background thread, doing some work to an object because it's status was
//set to Status_Modified
[managedObjectContext performBlockAndWait:^{
object.status = Status_NotModified;
[managedObjectContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
[managedObjectContext save:&error];
}];
What if while this is going on, on the main thread, the status is set to Status_Modified and saved? Will the objects status stay as Status_Modified? I.e. will the 'status' property be considered to be changed and so cause a conflict and therefore trump our in memory change (according to the policy)?
So, I cannot find any decent documentation to answer this question, but I have done some tests and it seems that the property is considered to be changed. This was my suspicion and seems to agree with various references to key-value setting being wrapped by will/didSetValueForKey:
My test:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSManagedObjectContext * uiCtx = [self contextForUIWork];
NSEntityDescription * entityDesc = [NSEntityDescription entityForName:#"Entity" inManagedObjectContext:uiCtx];
Entity * entity = [[Entity alloc] initWithEntity:entityDesc insertIntoManagedObjectContext:uiCtx];
entity.testproperty = #(1);
NSError * error = nil;
[uiCtx save:&error];
if (error)
{
assert(0);
}
NSManagedObjectID * objID = entity.objectID;
[self doStuffToObjectWithIDOnAnotherThreadAndAnotherContext:objID];
entity.testproperty = #(2);
[uiCtx setMergePolicy:NSErrorMergePolicy];
error = nil;
[uiCtx save:&error];
if (!error)
{
//We do not hit this! Success!
assert(0);
}
}
-(void)doStuffToObjectWithIDOnAnotherThreadAndAnotherContext:(NSManagedObjectID*)objID
{
dispatch_barrier_sync(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
NSManagedObjectContext * bgCtx = [self contextForBackgroundWork];
Entity * bgEntity = (Entity*)[bgCtx objectWithID:objID];
[bgCtx performBlockAndWait:^{
//set to same value
bgEntity.testproperty = bgEntity.testproperty;
NSError * bgError = nil;
[bgCtx save:&bgError];
if (bgError)
{
assert(0);
}
}];
});
}
(Full test code uploaded here: https://github.com/samskiter/CoreDataValueChangingTest )
A citation from the docs confirming this would be far better than just some test that shows it works on this particular version of 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.
I am working with Blackraccoon FTP client to do FTP operations,working with ARC.but i am getting leaks in instruments.
but there were no leaks in sample application here is my code
BRRequestCreateDirectory *createEventDir = [BRRequestCreateDirectory initWithDelegate:nil];
//NSString *EventCode = [[NSUserDefaults standardUserDefaults] stringForKey:kEventCodeKey];
createEventDir.path = #"/12341234";
createEventDir.hostname = #"media.example.com/httpdocs/events/";
createEventDir.username = #"badboy";
createEventDir.password = #"hai!";
createEventDir.tag = 103;
[createEventDir start];
createEventDir = nil;
sample code from FTP clent Blackraccoon FTP client
leaks showing in instruments like,but i am using ARC
can any one help me to solve this prob..
I ported and heavily modified BlackRaccoon. It is designed to use delegates. In other words, delegates are required.
BRRequestCreateDirectory *createEventDir = [BRRequestCreateDirectory initWithDelegate:nil];
//NSString *EventCode = [[NSUserDefaults standardUserDefaults] stringForKey:kEventCodeKey];
createEventDir.path = #"/12341234";
createEventDir.hostname = #"media.example.com/httpdocs/events/";
createEventDir.username = #"badboy";
createEventDir.password = #"hai!";
createEventDir.tag = 103;
[createEventDir start];
createEventDir = nil;
Is incorrect. It starts a lot of things going and then deletes the object - the action is undefined.
Instead you need something as indicated in the code that I provided (that doesn't leak).
First, the class that uses the ftp needs to have BRRequestDelegate to indicate the delegate protocol.
- (IBAction) createDirectory:(id)sender
{
//----- createEventDir must be a variable in your class...
createEventDir = [BRRequestCreateDirectory initWithDelegate: self];
createEventDir.path = #"/12341234;
createEventDir.hostname = #"media.example.com/httpdocs/events/";
createEventDir.username = #"badboy";
createEventDir.password = #"hai!";
[createEventDir start];
//----- createEventDir MUST NOT BE DELETED OR SET TO NIL HERE
}
Then you have to have the two delegates (at a minimum):
-(void) requestCompleted: (BRRequest *) request
{
//----- handle Create Directory
if (request == createEventDir)
{
NSLog(#"%# completed!", request);
//----- everything is done, NOW you can set it to nil
createEventDir = nil;
}
}
-(void) requestFailed: (BRRequest *) request
{
if (request == createEventDir)
{
NSLog(#"%#", request.error.message);
//----- everything is done, NOW you can set it to nil
createEventDir = nil;
}
}
If you go back and look at my test code you'll see how things work. If you are still having issues, post in the issues on http://github.com/lloydsargent/BlackRaccoon
Hopefully this will get you past your problem.
I'm beginning coding with the DeviceMotion class. After following Apple's documenation, i have the following:
- (void)viewDidLoad {
[super viewDidLoad];
myMM = [[CMMotionManager alloc] init];
myMM.deviceMotionUpdateInterval = 1.0/30.0;
theQ = [[NSOperationQueue currentQueue] retain];
motionHandler = ^ (CMDeviceMotion *motionData, NSError *error) {
if (motionData.rotationRate.z > 5.5 || motionData.rotationRate.z < -5.5) {
NSLog(#"Rotation of Z."); // Reference A
}
};
-(IBAction)toggleClick{
NSLog(#"toggle");
if(myMM.gyroAvailable){
if(myMM.deviceMotionActive){
NSLog(#"Stopping Motion Updates..");
[myMM stopDeviceMotionUpdates];
} else {
NSLog(#"Starting Motion Updates..");
[myMM startDeviceMotionUpdatesToQueue:theQ withHandler:motionHandler];
}
}
else {
NSLog(#"No motion available. Quit!");
}
This code works fine, however when I want to do any code except an NSLog (even something as simple as incrementing an integer) in place of the 'reference A', I get an EXEC Bad Access in the console.
I've looked around, and all I've found is that it's a memory leak of sorts. Does anyone know whats going on? If not, how can I figure it out? I'm pretty inexperienced with Instruments, but if I'm pointed in the right direction I'd be much appreciated.
EXC_BAD_ACCESS is an OS-level exception meaning that you are trying to access memory that doesn't belong to you. I think this has something to do with your block being local to the scope, so once it goes out of scope, it is destroyed. You need to create a copy of it on the heap.
Try this answer from the renowned Dave DeLong. Also, as with the normal Cocoa memory management rules, don't forget to release it if you've made a copy.
For example:
motionHandler = Block_copy(^ (CMDeviceMotion *motionData, NSError *error) {
if (motionData.rotationRate.z > 5.5 || motionData.rotationRate.z < -5.5) {
NSLog(#"Rotation of Z."); // Reference A
}
});
// and then later:
- (void) dealloc
{
[motionHandler release];
//and all others.
[super dealloc];
}