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.
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.
It's the first time I have to fix a memory problem from one of my iOS apps, so I'm not really sure how to track it, I've been reading some post from different blogs and I've found that my memory is constantly increasing:
The problem is that I don't know how to track and fix the problems in my code, and I also don't know what should be the best "Growth" in memory. Thank you.
First, I'd recommend watching WWDC 2013 Fixing Memory Problems and WWDC 2012 iOS App Performance: Memory videos. They are dated, yet still relevant, demonstrating of taking the above screen snapshot down to the next level in order to identify the underlying source of the memory issue.
That having been said, I have a couple of observations:
In my experience, nowadays, the problem is rarely "leaked memory" (i.e. memory that has been allocated, for which there are no more references, but you neglected to free it). It's rather hard to leak in Swift (and if you use the static analyzer on Objective-C code, the same it true there, too).
The more common problem is "abandoned memory" resulting from strong reference cycles, repeating timers not getting invalidated, circular references between view controller scenes, etc. These won't be identified by the Leaks tool. Only by digging into the Allocations tool.
First, I often like to see what accounts for the bulk of the abandoned memory. So I double click on a top level call tree and it will show me where the abandoned memory was allocated:
Note, this doesn't tell me why this was abandoned, but by knowing where the bulk of the abandoned memory was allocated, it gives me some clues (in this example, I'm starting to suspect the SecondViewController).
I then drill into the generations results and start by looking for my classes in the allocations (you can also do this by manually selecting a relevant portion of the allocations graph, as discussed here). I then filter the results, searching for my classes here. Sure, this won't always be the most significant allocation, but in my experience this sort of abandoned memory almost always stems from some misuse of my classes:
Again, this is pointing me to that SecondViewController class.
Note, when looking at generations, I generally ignore the first one or two generations because they may have false positives stemming from the app "warming up". I focus on the latter generations (and make sure that I only "mark" a generation when the app has been returned to some-steady, quiescent state.
For the sake of completion, it's worth pointing out that it's sometimes useful running Instruments with the "Record reference counts" feature on the unreleased allocation:
If you do that, you can sometimes drill into the list of retain and release calls and identify who still has the strong reference (focus on unpaired retain/release calls). In this case it's not very useful because there are just too many, but I mention in because sometimes this is useful to diagnose who still has the strong reference:
If you're using Xcode 8, it has a brilliant object graph debugger that cuts through much of this, graphically representing the strong references to the object in question, for example:
From this, the problem jumps out at me, that I not only have the navigation controller maintaining a reference to this view controller, but a timer. This happens to be a repeating timer for which I neglected to invalidate. In this case, that's why this object is not getting deallocated.
In the absence of Xcode 8's object graph debugger, you're left to pouring through the retain and release references (and you can look at where each of those strong references were established and determine if they were properly released) or just looking through my code for things that might be retaining that particular view controller (strong reference cycles, repeating timers, and circular view controller references are the most common problems I see).
Minimizing your app's Memory Footprint
For the benefit of both stability and performance, it's important to understand and heed the differing amounts of memory that are available to your app across the various devices your app supports. Minimizing the memory usage of your app is the best way to ensure it runs at full speed and avoids crashing due to memory depletion in customer instantiations. Furthermore, using the Allocations Instrument to assess large memory allocations within your app can sometimes be a quick exercise that can yield surprising performance gains.
Apple Official Document
I am working on one application which has lots of screens, custom views and API calls on almost each screen. Sometimes when the user uses the app for a long time, it gets crashed because of Out of Memory issues.
Ideally, I followed all guidelines while developing app and ARC takes care of memory usage. So what are the best way to avoid such memory issues?
Code has a built-in memory profiler that can help you with this issue - for a tutorial on how to use it, this might be helpful http://www.raywenderlich.com/23037/how-to-use-instruments-in-xcode
Otherwise, if dealloc isn't being called it could be a symptom of a retain cycle (two objects maintain strong references to each other, so they are never deallocated).
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.
I am finding it very hard to get the details of how memory management is done in BADA OS.
Does anyone have any info about it or do all smart-phones have similar memory management concepts?
Programming on bada you mainly have to deal with heap-memory. In some classes of bada-API you have to use automatic memory management (Osp::Base::Collection can release memory of its elements if you want; in Osp::Ui::Container method RemoveControl() will free memory of his child ).
But in general cases you need handle memory freeing by yourself.
Memory management in BADA follows the conventional C++ memory handling policy.
An app is always responsible for deleting memory it allocates (every call to new must have
a symmetrical call to delete)
Memory in BADA at runtime is divided between:
Static memory
:Assigned by the compiler and is part of the application binary at runtime.
Stack memory:Allocated and freed at runtime by the OS as function activation frames for the running program are created and released
Heap memory:Allocated and freed dynamically as requested by a program.
Object Ownership Responsibilities
A further small, but important, complication relating to memory allocation and object
construction is that sometimes framework methods require the framework to allocate and
return a new object to the calling app.
However, once the object is returned by the framework, and the object is passed into the
ownership of the caller, the framework no longer knows when the object is finished with.
In this case, the simple rule that allocating and freeing memory should always be done
symmetrically no longer holds.
The problem for the app programmer is, then, to know whether or not the app, or the
framework, should be responsible for cleaning up a given object.
This problem is solved almost trivially in BADA by a simple naming convention, and the
associated rule
Convention
Trailing ‘N’ in a method name, for example: Sometype() to SomethingN()
Rule
The caller is always responsible for deleting objects returned by a framework method
named with a trailing ‘N