Python for the .NET Developer Transcripts
Chapter: Memory management in Python
Lecture: Memory management in .NET
0:00 Let's begin with a high-level overview of how memory management and the garbage collector works in C# and really in .NET. As I said at the onset
0:10 there's no explicit memory management necessary for the most part in .NET and C#. There's an unsafe mode where you can work with pointers
0:19 and pin references and things like that but that keyword is extremely rare in the language and people almost never use it.
0:26 So let's just assume explicit memory management not really a thing, we're just going to let the garbage collector manage memory for us.
0:33 Now, one of the really important distinctions in .NET is between the different types of variables or values you can store.
0:42 Data is broken into two categories. Most things are reference types they're allocated on the heap they're dynamically allocated
0:50 their references can be passed around they can be allocated one place and be kept alive by another. On the other side we have value types.
0:59 These are mostly like numbers and booleans and stuff these are passed by value, they're allocated on the stack and they're not kept alive
1:07 they're not even subject to garbage collection at all. So value types on the stack, reference types on the heap.
1:14 When a function returns, the stack is destroyed the value types are gone. So you don't really have to think about this idea of value types
1:21 for this memory management story, right? It's like, it's a different thing. So we're only focused on the reference types.
1:28 Now, .NET has a garbage collector it's going to run when memory pressure is high. Well, what defines memory pressure?
1:34 Mostly it's when the generation 0 gets full, right? It just going to keep allocating at generation 0. Generation 0 is small, it's like 16 megabytes
1:44 or something, potentially even smaller I don't exactly remember the exact numbers and they change a little bit over time, I suspect.
1:50 But, when enough allocations have happened it's going to run depending on how it's run previously how much memory pressure there is
1:58 it might do a small collection, like Gen 0 or it might do a full collection, a Gen 2 collection. When there's enough memory pressure
2:04 then the garbage collector decides it's time to kick in, go do it's thing and it's going to run one of these collections. The algorithm that uses
2:12 what's called a mark-and-sweep algorithm. So the garbage collector doesn't actually go around and collect garbage.
2:17 What it does is it goes around and find objects that are still around and then it assumes stuff that is in the gaps that must have been garbage
2:25 so we're going to forget about it. But it doesn't actually track the garbage it actually only tracks the live things.
2:30 As I indicated before there's actually three generations Gen 0, 1 and 2. And as objects survive, a collection they get promoted
2:37 from like 0 to 1 and 1 to 2 and so on. There's a few edge cases that don't quite follow that rule like large objects and so on.
2:44 In general, things start out in a probably trash bin called Gen 0, and then once they survive that they go to Gen 1 and Gen 2
2:53 and there's fewer collections as you get up in the higher bits. There's a lot more memory that has to be looked at
2:58 in order to do a Gen 2 collection than say a Gen 0. A really important part of garbage collection type of algorithms is that memory management
3:06 and memory clean up is non-deterministic. That means I could run almost the same program multiple times and under very slight variations
3:15 it might actually behave differently, right? There might be different pauses based on maybe you go to a different size of input
3:22 but to the same algorithm. Timing and order of when these garbage collections happen is non-deterministic, usually you don't care
3:30 usually they're fast, but certain circumstances where you're doing real-time type programing or something like that
3:36 this potentially could cause some trouble. Finally, a very nice feature of .NET's garbage collector is that it compacts memory.
3:46 So, I've allocated a bunch of objects. They're likely, if they're allocated at the same time to be related to each other.
3:51 And the stuff that was potentially allocated in between them when it becomes garbage the memory is actually moved
3:57 and squished down like an accordion back together and the stuff that was allocated and survived next to each other is even closer potentially
4:05 than it was before. This can help a lot with memory fragmentation and it's a pretty cool feature of .NET.
4:10 So, hopefully this gives you a good sense of .NET's memory management story this is generally how things work over there.