I am trying to learn about Memory Management in iOS development. I read this article / tutorial: Make Memory Management Great Again
In that tutorial, there is a deinit method inside a class, like this:
class Human {
var passport: Passport?
let name: String
init(name: String) {
self.name = name
}
deinit {
print("I'm gone, friends")
}
}
After we make an instance, the reference count is one because it is a strong reference. until this step, I understand.
var bob: Human? = Human(name: "Bob Lee")
It is said that when we make an instance, it actually takes space in our RAM.
If we assign nil to 'bob' variable, the deinit will print ("I'm gone, friends"), and the relationship no longer exists, so the reference count becomes 0 which causes both objects to be deallocated.
The things that makes me confused:
in my actual code / from tutorial I follow, I never see 'deinit' in my class, and I never assign nil to the instance, so the object will never be deallocated and it will take space in my memory like fat? should I write deinit in my code? because I think if over limited of space, it would be filled with data objects and eventually my app would break
it is said that:
Automatic Reference Counting to indicate whether an object is still
being used or no longer needed
No longer needed? What does it mean?
Just to clarify from your example:
var bob: Human? = Human(name: "Bob Lee")
// bob now has a reference count of 1
// the memory at the bob location is ready to access and/or modify
// this means bob is still alive and we can find out things about him
print(bob!.name)
// prints "Bob Lee"
bob = nil
// deinit called, "I'm gone, friends"
// bob now has a reference count of 0, and ARC has released the object that was stored here
// we cannot find out anything about bob
// the memory at the location of bob is now released
print(bob!.name)
// Error: Unexpectedly found nil while unwrapping optional value
To answer your questions:
If you never need to assign nil to bob (it might not make sense depending on the context), you should assign the type of bob to be Human, not Human?. This means that bob can never, and will never be nil, and makes your code much easier to reason about. This does not mean that the Human object located at bob will never be gone from memory though. If bob is, for example, inside a view controller that at some point is deallocated (if the user navigates away from that VC or the app is closed), bob will of course also be deallocated by the system.
"No longer needed" means 'needed' from an access perspective from your code. If bob is set to nil, why would you need to access information about him again? You don't, so the object located at bob has its reference count reduces to 0, is no longer needed, and is deallocated.
I hope I could clear some things up for you.
Related
I just followed a tutorial on ARC and was provided with this code.
The following ViewController class and below it a Vehicle class.
What i got from it was that ARC essentially tracks down an instantiated class and allocates a piece of memory for it. As "strong" references for the instance are created, arc increases the increment for how many references there are to the instance. Once all of them are set to nil, ARC deallocates the instance from memory. The instructor also said something along the lines of, once all references are not being used, it deallocates from memory. I did not quite understand the part where they're not being "used", so I decided to add a button which presents another View Controller thats blank with no code. I figured that if I navigate to the next view controller, deinit will get called as the references in view controller 1, are now not being used and thus deallocated from memory. This was not the case, and the deinit did not get called. Therefore, I'm wondering, do references stay in memory unless you set them to nil, always?
Part 2 of question : Also, while you're answering that question, I also have another, I was also wondering if ARC only applied to class instances and references to it since every piece of documentation or tutorial that I have looked up seems to only mention class instances. For example, if I set var number = 2
var othernumber = number , is "number" also stored in memory, and only deallocated until all references to it are nil. If this is also the case, then the same question applies, is setting all references equal to nil the only way of deallocating from memory? Sorry for the lengthy question, but im quite new to the memory concept.
import UIKit
class ViewController: UIViewController {
var ref1: Vehicle?
var reference2: Vehicle?
var ref3: Vehicle?
var timer: NSTimer!
var count = 0
override func viewDidLoad() {
super.viewDidLoad()
ref1 = Vehicle(kind: "Car")
reference2 = ref1
ref3 = ref1
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(tick), userInfo: nil, repeats: true)
}
func tick() {
count++
if count >= 3 {
ref3 = nil
reference2 = nil
}
if count == 5 {
ref1 = nil
}
}
}
class Vehicle {
let type: String
init(kind: String){
self.type = kind
print("\(type) is being initialized")
//when the class is instantiated, we get an initialization message. When class is deallocated, we get a deinit message. As in, all strong references are gone, we can deinitialize.
}
deinit {
//class vehicle not in memory anymore as all strong references to it have been destroyed. This will be tested with segue as well.
print("\(type) is being deinitialized")
}}
The "used" terminology is confusing/misleading (or, at best, imprecise). With ARC, the object will not be released until there are no remaining strong references, plain and simple. If you nil all of those strong references, or those strong references fall out of scope, that's when the object is deallocated.
By the way, be aware that scheduledTimerWithTimeInterval establishes its own strong reference to its target. You have to invalidate the timer to resolve that strong reference.
ARC only applies to reference types (i.e. class instances). It simply does not apply to value types (such as numeric types or struct types).
Thus, consider
var number = 2
var othernumber = number
The othernumber does not reference the number. It makes a copy. It is a new object whose value happens to be the same value as number. For a discussion differentiating Swift value types from reference types, see WWDC 2015 Building Better Apps with Value Types. (By the way, the behind the scenes memory management of complex value types is actually more complicated than it is for simple value types, but it's not really relevant in this conversation. But it is discussed in some detail in the video if you're interested.)
This is a big question.
In order to understand ARC you really need to understand manual reference counting.
Reference counting is a way of keeping track of which objects are still in use, and which can be deallocated.
In manual reference counting, objects have a retain count.
You send a retain message to an object to increase it's retain count, and release to decrease it's retain count. If sending a release message to an object causes it's retain count to drop to 0, the object is deallocated/freed.
There is also an autorelease message which adds the object to an "autorelease pool". Each time your code returns and the event loop is visited, all the objects in the autorelease pool get sent a release message for each time they are in the autorelease pool. (You can send more than one autorelease message to an object, but ignore that.) Autorelease is useful for returning temporary objects that go away if you don't do anything special with them. An autoreleased object sticks around during the current call chain, but get freed when your code returns if nobody has retained it.
Objects are created and returned to the owner with a reference count of 1, and the owner is responsible for sending a release message to the object when it is done with it.
In manual reference counting you have to put retain, release, and autorelease calls in your code at the correct places in order to express your memory management intentions. Getting it wrong causes either memory leaks or crashes.
ARC uses all of the above mechanisms, but the compiler analyzes your code and inserts retain, release, and autorelease calls for you. It also strips out excess retain/release calls to the bare minimum required.
In ARC, you just need to declare your variables as strong or weak and the compiler does the rest. There are still a few gotchas, but for the most part you don't have to worry about memory management.
Storing an object in a strong variable causes the compiler to generate a retain call. Zeroing out the strong variable causes the compiler to send the object a release message.
Unlike garbage collection, the system doesn't have to stop and do time-consuming cleanup passes on memory. Objects get freed as soon as there are no longer any strong references to them.
There are some retain cycle in my iOS application.
For a particular viewController, stuck in a retain cycle, I have tried making all delegates weak. But when I simulate memory warning from simulator , didRecieveMemoryWarning is called , but deinit method is not called .
I want to print/see the owner of that viewController that is still holding it when didRecieveMemoryWarning is called. Is there any way I can do this.
If you are on Xcode 8 you can use the Memory Graph Debugger to visually see the active memory graph for objects in your projects. You can get to the Memory Graph Debugger by using the three circle icon shown below.
The Memory Graph Debugger was highlighted at WWDC 2016 in the following lecture, starting around 24:30.
https://developer.apple.com/videos/play/wwdc2016/410/
No there is not a way to print the owners of an object as you describe, at least not exactly. iOS does not use garbage collection, it uses ARC (Automatic Reference Counting.) The system doesn't track owning references in ARC. Instead, each time you add an owning reference to an object the system increases a retain count, and every time you clear an owning reference the system decrements that retain count.
What you can do, though, is run your program with the memory instrument. (There is a debugging application called "Instruments", you pick a debugging template called an "instrument" that you use within the Instruments program.) With the memory instrument you can follow the life-cycle of an object, as well as tracking the number of active objects in your app's heap.. When you select an object in the list of currently active object you can see where in your program it was allocated and where the code that creates strong references comes from. Explaining how to use Instruments is beyond the scope of an SO post however. There are various tutorials and WWDC session videos on the subject. I suggest doing some searching.
As to your question, forcing a low memory warning would not cause an active view controller (one that is on-screen) to be released and it's deinit method to be called. The system maintains a strong reference to the view controller.
Also, you should make delegate references weak by default. Having a delegate reference be a strong reference is VERY unusual. I've only seen it once or twice, for specific reasons.
You can make a print on the deinit method like
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) is being initialized")
}
deinit {
print("\(name) is being deinitialized")
}
}
You can check this: Automatic Reference Counting
I have this from either the Apple documentation or the swift book
When an instance gets deinitialized, you still have access to the
properties inside the instance and can manipulate them as needed
before the instance totally goes away.
I'm confused, do they mean when we for example do some mathematical action using the instances property in the deinit() method? or lets say when we print a property of type string that was part of a specific instance, also from the deinit() method?
If so, then is the deinit() method the only way to manipulate a property when it is being deinitialized?
if you have a swift class with a a var you know you have to clean up after because ARC can't free it (e.g. C memory), you can still do that in deinit. The pointers stored in the properties are still valid!
it isn't useful for much more though (ok end observing with the notification center or kvo) BECAUSE there is no guarantee WHEN deist is called. ONLY that it is called before deallocation [whenever that is]
deinit is called right before deallocation (when the retainCount reaches 0), so all your properties are still valid and you can print your string. You don't need to set properties to nil explicitly in deinit as that happens automatically.
This being said, most classes don't even need deinit implemented
Most of the time I used deinit to remove observer that the instance is registered to, post any notifications if needed, and things like that.
As far as I know, the deinit method gets called just before the instance gets deinitialized, to give you a final opportuninty to do whatever you need to do (cleanup, close a file, terminate a network connection, etc).
What the documentation says is that, at the time deinit is called your object has not been deinitialized yet (but will be very soon), so you still can (for the last time) access its properties.
In a non ARC Objective C environment, I understand why we have to release an object: to free the memory allocated for it; I understand why we have to set it to nil afterwards (if we are sure nothing else needs the instance / nothing else still has a hold on the object): to avoid dangling pointers.
However my question is, if all objects release their hold on an object, "carInstance" for example, resulting in its reference count going down to 0, why oh why does that Not automatically make it nil?
If reference count is now 0, is the object still usable in any way? Or is this just one of those things we have to do just because that's how not having garbage collection works (can't be, there must be a reason)
The simple answer is that the manual memory management model that was used pre-ARC is lightweight and simple. The behavior you are wishing for is the behavior you get with weak pointers under ARC; and it requires extra work by the OS, to track weak pointers and nil them out when the object is reclaimed. It's doable, clearly, but the cost of implementing it, as well as the computational overhead, wasn't deemed worthwhile until Apple was already rolling out the extra work of implementing ARC.
After an object is deallocated, the dangling pointer is worse than useless: it is downright dangerous. Referencing it while it points to unallocated memory produces an exception; referencing it after it is randomly reassigned to another object or some other memory allocation will typically produce an 'object does not respond to selector' error.
I haven't found a simple answer for these two questions:
do I have to remove a listener before deleting the property instance (the listener is not used anywhere else)?
BooleanProperty bool = new SimpleBooleanProperty();
bool.addListener(myListener);
bool.removeListener(myListener); // is it necessary to do this?
bool = null;
do I have to unbind a uni-directional bounded property before deleting the property instance?
BooleanProperty bool = new SimpleBooleanProperty();
bool.bind(otherBool);
bool.unbind(); // is it necessary to do this?
bool = null;
Case 1
Given that myListener "is not used anywhere else" and therefore I assume, a [method-] local variable, the answer is no. In the general case though, the answer is mostly a no but can sometimes be a yes.
As long as myListener is strongly reachable, then it will never become eligible for finalization and it will continue to consume memory. For example, this would be the case if myListener is a "normally" declared static variable (*all "normal" references in Java are strong references*). However, if myListener is a local variable, then the object will not be reachable anymore after the return of the current method call and bool.removeListener(myListener) is a bit meaningless over-engineering. Both the observer and the Observable goes out of scope and will eventually be finalized. A quote from my own blog post about this answer might paint a better picture:
It doesn’t matter if the box know about the cat inside of it, if you
throw the box into the ocean. If the box isn't reachable, nor is the
cat.
Theory
To fully understand the situation here, we have to remind ourselves of the life-cycle of a Java object (source):
An object is strongly reachable if it can be reached by some thread
without traversing any reference objects. A newly-created object is
strongly reachable by the thread that created it. [..] An object is
weakly reachable if it is [not] strongly [..] reachable but can be
reached by traversing a weak reference. When the weak references to a
weakly-reachable object are cleared, the object becomes eligible for
finalization.
In the case of static variables, these will always be accessible as long as the class is loaded, thus reachable. If we didn't want a static reference to be the one that hinder the garbage collector to do his job, then we could declare the variable to use a WeakReference instead. JavaDoc says:
Weak reference objects [..] do not prevent their referents from being
made finalizable, finalized, and then reclaimed. [..] Suppose that the
garbage collector determines at a certain point in time that an object
is weakly reachable. At that time it will atomically clear all weak
references to that object [..]. At the same time it will declare all
of the formerly weakly-reachable objects to be finalizable.
Explicit management
For illustration, let's assume that we write a JavaFX space simulation game. Whenever an Observable planet moves into the view of a spaceship observer, the game engine register the spaceship with the planet. It is quite apparent that whenever the planet goes out of view, the game engine should also remove the spaceship as an observer of the planet by using Observable.removeListener(). Otherwise, as the spaceship continues to fly through space, memory will leak. Eventually, the game cannot handle five billion observed planets and it will crash with an OutOfMemoryError.
Do note that for the vast majority of JavaFX listeners and event handlers, their life-cycle is parallel to that of their Observable so the application developer has nothing to worry about. For example, we might construct a TextField and register with the text field's textProperty a listener that validate user input. As long as the text field sticks around, we want the listener to stick around. Sooner or later, the text field is not used anymore and when he is garbage collected, the validation listener is also garbage collected.
Automatic management
To continue on the space simulation example, assume that our game has limited multiplayer support and all the players need to observe each other. Perhaps each player keep a local score board of kill metrics or perhaps they need to observe broadcasted chat messages. The reason is not the important point here. What would happen when a player quit the game? Clearly, if the listeners are not explicitly managed (removed), then the player who quit will not become eligible for finalization. The other player's will keep a strong reference to the offline player. Explicit removal of the listeners would still be a valid option and probably the most preferred choice for our game, but let's say that it feels a bit obtrusive and we want to find a more slick solution.
We know that the game engine keep strong references to all players online, for as long as they are online. So we want the spaceships to listen for changes or events of each other only for as long as the game engine keep the strong references. If you read the "theory" section, then surely a WeakReference sounds like a solution.
However, just wrapping something in a WeakReference is not the entire solution. It seldom is. It is true that when the last strong reference to the "referent" is set to null or otherwise become unreachable, the referent will be eligible for garbage collection (assuming that the referent cannot be reached using a SoftReference). But the WeakReference is still hanging around. The application developer need to add some plumbing so that the WeakReference itself is removed from the data structure he was put in. If not, then we might have reduced the severity of the memory leak but a memory leak will still be present because dynamically added weak references consume memory too.
Lucky for us, JavaFX added interface WeakListener and class WeakEventHandler as a mechanism for "automatic removal". The constructors of all related classes accept the real listener/handler as provided by client code, but they store the listener/handler using a weak reference.
If you look at the JavaDoc of WeakEventHandler, you'll notice that the class implement EventHandler, so the WeakEventHandler can be used wherever an EventHandler is expected. Likewise, a known implementation of a WeakListener can be used wherever an InvalidationListener or a ChangeListener is expected.
If you look into the source code of WeakEventHandler, you'll notice that the class is basically only a wrapper. When his referent (the real event handler) is garbage collected, the WeakEventHandler "stop working" by not doing anything at all when WeakEventHandler.handle() is called. The WeakEventHandler doesn't know about which object he has been hooked up with, and even if he did, the removal of an event handler is not homogeneous. All known implementing classes of WeakListener has a competitive advantage though. When their callbacks are invoked, they are implicitly or explicitly provided a reference to the Observable they are registered with. So when the referent of a WeakListener is garbage collected, eventually the WeakListener implementation will make sure that the WeakListener itself is removed from the Observable.
If it is isn't already clear, the solution for our space simulation game would be to let the game engine use strong references to all online spaceships. When a spaceship goes online, all other online spaceships are registered with the new player using a weak listener such as WeakInvalidationListener. When a player goes offline, the game engine remove his strong reference to the player and the player will become eligible for garbage collection. The game engine doesn't have to bother about explicit removal of the offline player as a listener of the other players.
Case 2
No. To better understand what I'll say next, please read my case 1 answer first.
BooleanPropertyBase store a strong reference to otherBool. This in itself does not cause otherBool to always be reachable and thus potentially cause a memory leak. When bool becomes unreachable, then so do all its stored references (assuming they are not stored anywhere else).
BooleanPropertyBase also works by adding itself as an Observer of the property you bind it to. However, it does so by wrapping itself in a class that works almost exactly like the WeakListeners described in my case 1 answer. So once you nullify bool, it will be only a matter of time before it is removed from otherBool.
I completely agree with the case 1 answer, but the case 2 is a bit more tricky. The bool.unbind() call is necessary. If ommitted, it does cause a small memory leak.
If you run the following loop, the application will eventually run out of memory.
BooleanProperty p1 = new SimpleBooleanProperty();
while(true) {
BooleanProperty p2 = new SimpleBooleanProperty();
p2.bind(p1)
}
The BooleanPropertyBase, intenally, does not use a real WeakListener (an implementation of the WeakListener interface), it is using a half-baked solution. All the "p2" instances get eventually garbage-collected, but a listener holding an empty WeakReference remains in the memory forever for each "p2". The same holds for all properties, not only BooleanPropertyBase. It's explained here in detail, and they say it is fixed in Java 9.
In most cases, you do not notice this memory leak, because it leaves only a few dozen bytes for every binding that has not been unbound. But in some cases it caused me real trouble. An good example are table cells of a table that gets frequently updated. The cells then re-bind to different properties all the time, and these left-overs in the memory accumulate quickly.