According to Apple docs if an app ignores a memory warning, the system could force freeing the dirty memory, if it needs some. At the same time in some cases manual freeing the data in responce to the memory warning and later restoring it is not acceptable for the performance reason. So is it possible to know if certain class instance members were actually forcedly cleared? Are they assigned nil? And what about the pointers to C++ objects being the members of Obj-C objects?
That's not how it works. The OS will free the memory by quitting your app. The OS can not go in and randomly delete objects, because it has no way of understanding which objects would be safe to clear and which ones wouldn't.
IIRC the only thing it sometimes does is unload a few view controllers' views (but not the actual controller object) that are stacked e.g. in a navigation controller and not currently visible. It can do that because it knows how to load these views and what ivars they are referenced by (because you told it via IBOutlet etc.), so it can and will actually NIL those.
Update: There are also some cache classes these days that will evict their objects on receiving a memory warning, but you would have to explicitly use those classes for your objects to be released.
Related
I have deinit method in all my VCs to check if they are being deinitialized or not
deinit {
print("\(self.description) successfully deinitialized")
}
When I logout, I see all my view controllers are deinitialized and my LoginViewController becomes the root view controller. But I can still see the RAM usage as 90MB. Every time I log in and logout, it keeps increasing.
Is it possible if my view controller has deinitialized, still it can have a memory leak?
What I know is, if the view controller is deinitialized, there is no memory leak. If there is a memory leak, the view controller will not deinitialize.
Am I wrong? Please help.
UPDATE: As per Luca's suggestion, and with the help of this answer, I found out the memory leaks. But I am not able to understand any of this. Is there any way to make it more readable?
There are three types of undesired memory issues:
Abandoned memory: This is memory that you do have some lingering strong references, but for which you no longer have access to these references. The typical example is a strong reference cycle.
This is very common problem in Swift projects. You find these using the “Debug Memory Graph” feature. See iOS app with ARC, find who is owner of an object or How to debug memory leaks when Leaks instrument does not show them?.
By the way, you’ve apparently confirmed that your view controllers are being released. That’s great if that’s the case. But they’re not the only object that can be entangled in a strong reference cycle. Any reference types can get caught up in reference cycles. Use the “Debug Memory Graph” feature and review your objects in the left panel and make sure there’s nothing there that shouldn't be. (By the way, this technique saves you from having to sprinkle deinit methods all over the place.)
Cached memory: This is memory that has been allocated, and the system will hang on to it in case you might need it again, offering you high performance access. This often isn’t too worrisome unless the amount of memory consumed is huge, because when the device is placed in memory pressure, often this memory is reclaimed automatically for you.
If you use UIImage(named:) that can cache images in memory. If you use URLSession, the URLCache can cache responses.
If testing on simulator, you might want to choose “Debug” » “Simulate Memory Warning” and see how much memory is retrieved, if any.
Leaked memory: This is memory that that has been allocated, but for which you have no further references to it. Typically this is a result of some manual allocation of memory that was never deallocated.
The Leaks tool will help you find these, but this is relatively uncommon to have anything material in this category in Swift code. (Or if you do have them, they tend to be small things generated within the frameworks, not within your control.) Sure, if you’re doing manual Core Foundation (or Core Graphics) calls, you can manifest these sorts of issues, but it’s not very common.
FWIW, the leaks tool doesn’t appear to be reporting any material memory consumption. So focus on Allocations tool (or, better, the “Debug Memory Graph”, if you can). Your leaks don’t appear to be enough to account for the sort of memory loss that you’re talking about here.
Also, I’d suggest you confirm that you do not have memory diagnostics turned on. E.g. things like zombies or the like can cause growth in memory (though I wouldn’t have thought that you could approach 90mb worth). Tools like this, the malloc stack trace, etc., increase memory consumption. That’s fine while using these tools to diagnose issues, but should be turned off when you’re done.
But, bottom line, I’d focus on confirming that the problem is not abandoned or cached memory, before diving into leaks (as often the latter are small and unrelated to anything in your code). These are far more common source of issues.
Even though the ViewController is de-initialised it doesn't necessarily mean it will be deallocated. There is a possibility there is a strong reference cycle. Or maybe in your code, to avoid retain cycle you are using unowned reference somewhere, for which the reference count is not becoming zero. The object will not be de-allocated until both strong and unowned reference counts become zero. In that case try using weak instead of unowned and see if it works. Weak references point to something called side table instead of directly pointing to the object, and hence don't keep the object from getting deallocated once de-initialised
Check out this article to understand how unowned reference can sometimes keep the object from getting deallocated, and ARC in general.
I am working on Xcode8 and Swift3. While running the app I am using visual memory debugging. It shows me 3 memory issues on left hand side. Please let me know how can I resolve these memory issues?
Well, it's really hard to tell you how to solve those issues without knowing the flow of your program. Plus, there are a lot of causes to memory issues, and it really depends on how you handled the instances of your object.
If you are not using ARC, the it means that you are responsible for releasing any object you created. Then you have to check in which stage did that object get leaked. As it stated there, it is a Dictionary that got leaked. So you have a clue on what specific object to check.
On the other hand, if you are using ARC, then you don't have to handle releasing of the objects that you created. But, it doesn't mean that you won't get any leaks. These are some possible causes that may cause a memory leak in your program even if using ARC:
You set a strong reference to a parent in a child object. This causes a retain cycle.
You set a strong reference to a delegate in an interface.
You forgot to release an object when you do a toll-free bridging after transferring ownership.
You forgot to set a weak reference to objects you passed in a block.
I hope this helps
I may have an incomplete understanding of using allocations in instruments. I am trying to debug a retain cycle. At key points in my app I use 'Mark Generation' .
I am looking for a subclass of a UIViewController that never has it's dealloc method called when it goes out of scope. Checking the generation data under generations shows a lot of stuff but no Objects that were allocated during execution.. in fact there is nothing that I recognise from my code in here, no UI objects whatsoever. Perhaps I have missed a setting that records these things somewhere?
I have a very custom project setting which uses one class with a delegate protocol. The main view creates dynamically about 100 objects of this class. For each object the main view controller is set as delegate of the object as the objects need to communicate with the main view controller.
I'm wondering if this can lead to any performance or memory issues caused by the use of the delegation pattern?
As long as the same main view is the delegate for all of your objects, the only memory consumption in this pattern are your newly created objects. The delegate references cost nothing in terms of reference, as they are just pointers to your existing main view controller.
With that said, in some circumstances, people do create specialized objects to act as delegates and if you follow that pattern (where you would allocate and maintain a separate delegate object for each "other" object), then you would see consumption and this pattern sometimes leads to leaks depending on how ownership is managed/mismanaged.
But, for the case described above, it should not be a problem.
Using the delegate or indeed any other pattern does not lead to performance issues or memory leaks. The intent of a pattern is to provide a commonly applied and tested solution to a specific problem, regardless of language, system, memory, etc.
Memory leaks and performance issues can occur in a system in which patterns have been used as easily as any other. But they are not the results of the patterns. They are a result of poor design or memory management.
Fro the case you describe I would not expect any performance issues to arise. Simply because the numbers of objects involved is quite small. However in-proper memory management will lead to memory leaks so you need to be aware of those.
My advice would be to re-read the memory management rules and run your code through the leaks tool in instruments.
In the Mac and iOS platforms, memory leaks are often caused by unreleased pointers. Traditionally, it has always been of utmost importance to check your allocs, copies and retains to make sure each has a corresponding release message.
The toolchain that comes with Xcode 4.2 introduces automatic reference counting (ARC) with the latest version of the LLVM compiler, that totally does away with this problem by getting the compiler to memory-manage your stuff for you. That's pretty cool, and it does cut lots of unnecessary, mundane development time and prevent a lot of careless memory leaks that are easy to fix with proper retain/release balance. Even autorelease pools need to be managed differently when you enable ARC for your Mac and iOS apps (as you shouldn't allocate your own NSAutoreleasePools anymore).
But what other memory leaks does it not prevent that I still have to watch out for?
As a bonus, what are the differences between ARC on Mac OS X and iOS, and garbage collection on Mac OS X?
The primary memory-related problem you'll still need to be aware of is retain cycles. This occurs when one object has a strong pointer to another, but the target object has a strong pointer back to the original. Even when all other references to these objects are removed, they still will hold on to one another and will not be released. This can also happen indirectly, by a chain of objects that might have the last one in the chain referring back to an earlier object.
It is for this reason that the __unsafe_unretained and __weak ownership qualifiers exist. The former will not retain any object it points to, but leaves open the possibility of that object going away and it pointing to bad memory, whereas the latter doesn't retain the object and automatically sets itself to nil when its target is deallocated. Of the two, __weak is generally preferred on platforms that support it.
You would use these qualifiers for things like delegates, where you don't want the object to retain its delegate and potentially lead to a cycle.
Another couple of significant memory-related concerns are the handling of Core Foundation objects and memory allocated using malloc() for types like char*. ARC does not manage these types, only Objective-C objects, so you'll still need to deal with them yourself. Core Foundation types can be particularly tricky, because sometimes they need to be bridged across to matching Objective-C objects, and vice versa. This means that control needs to be transferred back and forth from ARC when bridging between CF types and Objective-C. Some keywords related to this bridging have been added, and Mike Ash has a great description of various bridging cases in his lengthy ARC writeup.
In addition to this, there are several other less frequent, but still potentially problematic cases, which the published specification goes into in detail.
Much of the new behavior, based on keeping objects around as long as there is a strong pointer to them, is very similar to garbage collection on the Mac. However, the technical underpinnings are very different. Rather than having a garbage collector process that runs at regular intervals to clean up objects no longer being pointed to, this style of memory management relies on the rigid retain / release rules we all need to obey in Objective-C.
ARC simply takes the repetitive memory management tasks we've had to do for years and offloads them to the compiler so we never have to worry about them again. This way, you don't have the halting problems or sawtooth memory profiles experienced on garbage collected platforms. I've experienced both of these in my garbage collected Mac applications, and am eager to see how they behave under ARC.
For more on garbage collection vs. ARC, see this very interesting response by Chris Lattner on the Objective-C mailing list, where he lists many advantages of ARC over Objective-C 2.0 garbage collection. I've run into several of the GC issues he describes.
ARC won't help you with non-ObjC memory, for example if you malloc() something, you still need to free() it.
ARC can be fooled by performSelector: if the compiler can't figure out what the selector is (the compiler will generate a warning on that).
ARC will also generate code following ObjC naming conventions, so if you mix ARC and MRC code you can get surprising results if the MRC code doesn't do what the compiler thinks the names promise.
I experienced memory leaks in my application due the following 4 issues:
Not invalidating NSTimers when dismissing view controllers
Forgetting to remove any observers to NSNotificationCenter when dismissing the view controller.
Keeping strong references to self in blocks.
Using strong references to delegates in view controller properties
Luckily I came across the following blog post and was able to correct them: http://www.reigndesign.com/blog/debugging-retain-cycles-in-objective-c-four-likely-culprits/
ARC will also not manage CoreFoundation types. You can 'bridge' them (Using CFBridgingRelease()) but only if you are going to use it as an Objective-C/Cocoa object. Note that CFBridgingRelease just decrements the CoreFoundation retain count by 1 and moves it to Objective-C's ARC.
Xcode 9 provides a great tool for finding that kind of issues. It is called: "Debug Memory Graph".
Using it you can find your leaked object by class type and you can see clearly who holds a strong reference to it, by releasing it from there solves your problem. It is also detects memory cycles.
See more info about how to use it