Python for the .NET Developer Transcripts
Chapter: Memory management in Python
Lecture: Cycles and GC in Python demo
0:00 We saw how reference accounting worked and that is beautiful if there are no cycles that get abandoned.
0:07 Well, let's go and create some cycles and see what happens. Alright, first of all I'm going to disable the garbage collector because I want to
0:14 see that the cycles are a problem. So we're going to create actually two doomed objects. And remember, the dooms, they can take their friends so
0:23 this v2 is a friend of v1 but let's also reverse it v1 has some friends, one of them is v2. So, v1 points at v2 because of this
0:37 and v2 points at v1 because of that. That will create the cycle right there. Now, we'll go down here and we'll have a link to
0:46 both of these and let's change this to gc and we'll put two counts in here. So, we'll do that in v2. Let's also put the "Here's the End of the Method".
1:01 Now, nowhere in this method yet are we actually dereferencing these objects. Of course, we should get to the end of the method
1:08 and then potentially these things might get cleaned up. We'll see. Go ahead and run it again, actually, let's up a
1:16 little bit more space so it's super obvious over here. So, down here, notice we created doomed at 76. We created doomed at forty and we asked and
1:33 they both have two references. What are those two references? Well, it's the two objects, the two variables, that we're looking at.
1:41 Here. Here. v1 and v2, these two are each adding a reference but, then this one pointing back to v1 is adding a second to v1 and this one pointing back
1:54 to v2 is adding a second to v2. So, they each have two as we saw right there. And notice we get all the way to the end of the method
2:03 then this cleans up. Let's add one more thing here maybe in main. Let's print. Program Ending. Just so you can see actually this is full on shutdown of
2:16 Python that's actually cleaning up these objects. So, there nothing about the garbage collecting that is
2:20 actually happening here. Let's go and do a little bit more here. Let's actually empty these things out.
2:27 So remember, before the reason these levels went down is we actually... Well, let's stop pointing at those objects.
2:34 Let's see if that still works. So, v1 equals None. And what the heck, let's do v2 equals none as well.
2:46 Put step two. That is going to lower the reference count but it's going to go from two to one for each of them.
2:51 It's not going to be enough to get them to clean up. Method ending. Boom! That's it. It went from two, two to one, one.
3:01 That's not enough to get it to clean up. Well, let's turn the garbage collector on as in stop disabling it. I'll explicitly enable it.
3:09 Normally, you don't have to but just encase we were playing with it above and it's disabled, let's just be really clear.
3:15 Well, that didn't do anything, right? What happened? Unlike reference counting the gc is not deterministic, it runs when it needs to run.
3:24 In order to see the gc signals we actually have to force it. Just like you would have to do in .net
3:30 we'd have to say gc.collect. So, we can do the same here to trigger that non deterministic clean up.
3:36 Then again, almost all the time we do not have cycles reference counting is all we need it'll clean everything up.
3:43 But when we don't, we can have this gc. So, let's go down here and well put a print 3. What goes before three, is a gc Collect.
3:55 That should go look for all the cycles and find this one. It should clean them up. You should see doomed the two doomed objects explaining their death
4:02 or predicting their death. And here you have it. Alright, so we create that object. It's 2. And then we dereference the variable that is one and
4:09 we still have one, one for the cycle. But, then we call gc.collect, which goes and says Here's the cycle, we're going to clean it up
4:17 let's detach that and start killing them off. That's these two lines right here. And after the gc run now it's zero, before the end of the method.
4:26 The first example we looked at reference counting none of this was necessary. Reference counting completely solved it, but once you get these cycles
4:34 that's the problem with reference counting. Here we have Python's backup garbage collector kicking in we kicked it to kick in, but it would kick in
4:43 on it's own eventually to clean up these cycles and it works like a charm. That's memory management in Python. In some ways it's a lot
4:52 simpler than .net with the reference counting and in others with these cycles it's actually quite familiar.