I want to render PDFs on iOS and I'm getting a memory leak when I call CGPDFDocumentCreateWithURL(). I know this issue has been discussed before, but I don't know whether my conditions are different because I'm using ARC.
I've extracted and simplified the problem by running the following code on my viewDidLoad:
// Bridge resourceRef to ARC with no ownership change (still owned by ARC)
CFURLRef resourceRef = (__bridge CFURLRef) [NSURL fileURLWithPath:htmlPath];
CGPDFDocumentRef pdf;
pdf = CGPDFDocumentCreateWithURL(resourceRef);
CGPDFDocumentRelease(pdf);
// Do not need to release resourceRef because ARC will release it
Instruments tells me that the Leaked Object is a Malloc 48 Bytes, responsible by CoreGraphics. And the stacktrace has CGPDFDocumentCreateWithURL in it. Leaking means that there is object out there without an owner.
I've create a git repo with a replication of the problem:
https://github.com/indika/PDFLeaks
Any ideas. Would appreciate any help or 'pointers'.
resourceRef is going to be overreleased. Take a look at what you are doing.
1) Bridge resourceRef to ARC with no ownership change (still owned by ARC)
2) CFRelease on resourceRef
3) ARC also releases resourceRef
You don't need step 2
This is not a memory leak though, but an overrelease.
I made many mistakes, especially with double releasing the document reference. However, that wasn't the real critter in my situation.
I was loading a broken PDF! I was using pdftk to slice and merge pdf documents, and I was breaking the indexes. So remember, after merging a PDF with pdftk, repair the file with:
pdftk original output destination
Related
serial (a NSString *) is obtained using CFBridgingRelease
The file that has this code does not use ARC (-fno-objc-arc
compiler flag)
Will ARC take care of releasing this memory,
in-spite of the above flag, or it must be manually released? In
certain situation using release seems to be causing crash
(EXC_BAD_ACCESS) and the stack-trace shows some autoreleasepool
related code there.
NSString *serial = nil;
io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceMatching("IOPlatformExpertDevice"));
if (platformExpert) {
CFTypeRef serialNumberAsCFString =
IORegistryEntryCreateCFProperty(platformExpert,
CFSTR(kIOPlatformSerialNumberKey),
kCFAllocatorDefault, 0);
if (serialNumberAsCFString) {
serial = CFBridgingRelease(serialNumberAsCFString);
}
IOObjectRelease(platformExpert);
}
[serial release];
You should use the static analyzer (shift+command+B or choose "Analyze" on Xcode's "Product" menu) and it will tell you precisely what's wrong. And if you click on the icon next to the error message, it will show the trail of logic as to how it concluded there was an issue:
Note, as the Transitioning to ARC Release Notes says:
__bridge_retained or CFBridgingRetain casts an Objective-C pointer to a Core Foundation pointer and also transfers ownership to you.
You are responsible for calling CFRelease or a related function to relinquish ownership of the object.
__bridge_transfer or CFBridgingRelease moves a non-Objective-C pointer to Objective-C and also transfers ownership to ARC.
ARC is responsible for relinquishing ownership of the object.
So, you really shouldn't be using CFBridgingRelease at all with non-ARC code. The CFBridgingRelease available in manual reference counting "is intended for use while converting to ARC mode only." And if you look at the definition of this function in manual reference counting code, it really does an autorelease (simulating the clean up ARC would do for you). But as the documentation says, it's only intended while actively transitioning your code base to ARC.
But, as you can see, if that's doing an autorelease, and you manually release it as well, you're over releasing.
Bottom line, if you're writing manual reference counting code and you want to transfer ownership so you'll release it later, you should use CFBridgingRetain. If you replace CFBridgingRelease with CFBridgingRetain in your snippet and re-analyze your code, the warning will go away.
If you've written manual reference counting code, don't be disheartened when you first run the static analyzer, as you may see many issues pop up. But just plug through them, one-by-one, until you get a clean bill of health.
There are two things, which look strange:
The last [serial release]; looks strange. You have passed its value with CFBridgingRelease(). If you use ARC you can't send release. If you don't use ARC, you should set serial to nil after that, but I suppose you want use its value later. So you shouldn't release it.
I don't know IOServiceGetMatchingService() but you don't own it (see Get Rule). Thus, you shouldn't release it.
Edit: As #Rob stated in a comment below. You're owner of the service object after all, and you must release it. Strange times we live in.
I've began using Cocos2D v3.1 some days ago (was using v2 for my older projects), and there seems to be memory management issues when using ARC. When I profile my game, I see that my custom classes (subclassed from CCSprite) are released correctly; I have the exact same number of #persistent as the number of objects running in my scene. However, I saw that CCSpriteFrames number is constantly going up and never released. I looked around in the class CCSprite, and I found that there's no dealloc function (which can be logical because we are using ARC) but the CCSpriteFrame allocated for every sprite is never released, which means that I can stack up a good bunch of these objects, so my Memory usage keeps going up. Same thing for CCTexture when I am using particles.
So I was wondering if there's something I must do to dealloc those frames or if I am just not understanding something about ARC.
Thanks in advance for your answers!
P.S When my scene is replaced, dealloc is called in which I release all my objects by putting their references to nil, thus cascading through all my objects' dealloc method and releasing everything except CCSpriteFrame apparently.
I'm using ARC, and my application compiles and works without crashing. However, when I run an Analyze build, I am seeing these warnings. I come from PHP and JavaScript so naturally I have no idea what to do to fix this stuff. Can anyone help me out?
ARC needs some help when dealing with Core Foundation. Try this:
NSArray *linkedPeople = (__bridge_transfer NSArray *)ABPersonCopyArrayOfAllLinkedPeople(person);
and
NSDictionary *personDictionary = (__bridge_transfer NSDictionary *)(ABMultiValueCopyValueAtIndex(addressFromPerson, 0));
__bridge_transfer tells ARC that a non-Objective-C (i.e., Core Foundation) pointer is being moved to an Objective-C pointer, and it allows ARC to take ownership of the object for memory management purposes. CF functions with the word "copy" in them produce an object reference with a +1 reference count. If you don't explicitly call CFRelease() on the object later, then it will leak. Using __bridge_transfer, however, lets ARC do this for you.
(Note: I didn't test this, but I believe those are the issues that the static analyzer is complaining about.)
Yes, you can use:
NSArray *linkedPeople = (__bridge_transfer NSArray *)ABPersonCopyArrayOfAllLinkedPeople(person);
But Apple now recommends using:
NSArray *linkedPeople = CFBridgingRelease(ABPersonCopyArrayOfAllLinkedPeople(person));
It does the same thing, but Apple recommends you use the latter.
See WWDC 2012 session 405, 37:33 into the presentation.
So! Even though you're using Automatic Reference Counting (ARC), it's still a good idea to read up on Objective-C Memory Management:
http://longweekendmobile.com/2011/09/07/objc-automatic-reference-counting-in-xcode-explained/
But, for your specific problem:
Generally, when you see a C method in the Apple frameworks that has the word Copy in it, you're taking ownership of that Core Foundation type and you need to release it. When you want to release that type, just use:
CFRelease(addressFromPerson)
That's the first issue. Your screenshot cuts off the second error so I'm only speculating, but I think you also need to release your NSDictionary *personDictionary. Similarly:
CFRelease(personDictionary)
Note that you also need to manage the memory for linkedPeople
Normally ARC will take care of memory management for you, but when working with Core Foundation types, you still need to clean up after yourself.
I would strongly recommend you check out these great resources on memory management with ARC, particularly when dealing with CF types and toll-free bridging:
http://www.joergjacobsen.com/blog/2011/10/05/managing-toll-free-bridging-in-an-arced-environment/
http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html
I am pretty much a newbie to objective-c and as I started to program, I did not really grasp how to properly release objects. So, my project being an introduction into the world of Objective-c, I omitted it completely. Now, however, I think this project evolved in that it is too much of a pity to just leave it at that. So, all the allocs, copys and news aside, I have serious problems with understanding why my project is still leaking so much memory.
I have made use of the leaks tool in Instruments (look at screenshot), and it shows me that whole array of objects that are leaked. My question now: Is this something to be worried about, or are these objects released at some point ? If not, how do I find the cause of the leak ? I know that if I press cmd + e it shows me the extended detail window, but which of these methods should I look in ? I assume that it is my own methods I have to open up, but most of the times it says that i.e. the allocation and initialization of a layer causes the problem.
That said, I would like to know how to effectively detect leaks. When I look at the leaks bar of instruments, at the initialization of my game layer (HelloWorldLayer) a biiiig red line appears. However, this is only at it's initialization... So, do I have to worry about this ?
Here is the screenshot:
link to file (in order to enlarge) -> http://i.stack.imgur.com/QXgc3.jpg
EDIT:
I solved a couple of leaks, but now I have another leak that I don't quite understand :
for (int i = 1; i<=18; i++) {
NSMutableDictionary *statsCopy = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)stats, kCFPropertyListMutableContainers);
NSNumber *setDone = [num copy];
[levels setObject:statsCopy forKey:[NSString stringWithFormat:#"level%d", i]];
[levels setObject:setDone forKey:#"setDone"];
[statsCopy release];
[setDone release];
}
He happens to detect a leak with the deep copy, even though I release it...
The screenshot shows that there's a dictionary allocated in -[Categories init] that never gets released. Actually, there are many (2765) such dictionaries.
That method seems to be invoking -[NSDictionary newWithContentsOf:immutable:]. The stack trace here may be somewhat misleading due to optimizations internal to Cocoa. That's not a public method. It's probably called by another NSDictionary method with a tail call which got optimized to a jump rather than a subroutine call.
Assuming there's debug information available, Instruments should show you the precise line within -[Categories init] if you double-click that line in the stack trace.
Knowing where it is allocated is not the whole story. The Categories class may manage ownership of the object correctly. Some other class may get access to it, though, and over-retain or under-release it. So, you may have to track the whole history of retains and releases for one of those objects to see which class took ownership and neglected to release it. Note, this has to be done for one of the leaked dictionaries, not one of the malloc blocks that was used internally to the dictionaries. Go down two lines in the table for some promising candidates. Toggle open that line to see the specific objects. Double-click one or click the circled-arrow button next to its address (I forget which) to see the history of retains and releases.
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