I’m a guy talking and showing a lot of stuff about .NET memory management. I’ve wrote a book about it, I’ve done webinars, conference talks, infographics, a lot. Add there is ALWAYS at least one question like “Ok, that’s nice, but why should I care about it. It’s all automatic, isn’t it?”. Answering the same question again and again is pretty tiresome. Hence, I’ve eventually decided to make a webinar just about that – why should I care? Why should YOU care? If you have more than hour to watch it, I strongly invite you. But if you don’t, stay with me for a written version here.

First of all, I would rephrase the question – “Why should YOU care about learning and understanding tools you use…?”. Why should you care about async/await, database or ORM you use? In the end, what do you really need to know to program and earn money in a given technology?

Let’s pause this questions for a moment and let’s be clear about one thing – .NET GC (and automatic memory management in overall) is a convenient abstraction. As our dear Wikipedia says, an abstraction is “a simplification of something much more complicated that is going on under the covers”. And automatic memory management is a simplification of much more complex manual memory management – giving a promise you have an infinite amount of memory (you only allocate) and don’t care about freeing it. In IT we love abstractions. Abstractions simplify our lives, A LOT. But there is also The Law of Leaky Abstractions coined by Joel Spolsky (co-founder of StackOverflow and Trello) – “All non-trivial abstractions, to some degree, are leaky.

So, TCP is an abstraction of reliable connection built on unreliable IP. ORM like Entity Framework is an abstraction of classes and methods representing DB tables and SQL queries. And ASP.NET Web Forms has an abstraction of statefulness over stateless HTTP protocol with the help of ViewState. But if you have ever developed something bigger than school project, you were seeing those abstractions leaking. Observing TCP latency drops due to IP retransmissions, analyzing SQL queries generated by your ORM and being surprised how big your ViewState is transferred between the client and server again and again. Abstractions fail. We are fooled by abstractions. Sometimes they leak more, sometimes less.

Ok, so .NET GC abstraction leaks, too? But for sure someone will say: “I have been programming in C# for X years and have never needed to care about it…”. Where X is like 10, 20 or gazillion. But putting jokes aside, it makes sense. Because, as I said, abstractions make our lives so much easier! That’s it, that the result – you MAY not think about it and live.

That’s why “80% rule” works here – MOST of the time you don’t need to think about it. Until you need. Or until you want to for your own benefit.

You can be in “80%” of people that don’t care – that’s TOTALLY fine. But you can be in this “20%” of experts that do care! If someone says “I have been programming in C# for X years and have never needed to care about it”, I can reverse the question: what would you be working on IF you had cared about it during those X years? Maybe they were not measured, inefficient apps wasting resources and you could help saving some money for your company? Or maybe they were just pretty boring apps? Or maybe you could just be a better Software Craftmanship, caring to deliver not only working software, but well-crafted working software? I believe this all leads to one crucial question – do you want to be an expert or a regular developer? If you want to be just a regular .NET developer, absolutely, YMMV!

Ok, let’s pause for a moment. There is one more aspect of it… There are two main perspectives you can look at it:

  • application developer perspective – what’s said above perfectly suits here. “You don’t have to care about until it becomes a problem” 👍 You are on good position here – you know your application, its context, requirements, current and expected workload. You can measure it (if you know how…). You know what are the bottleneck. So, the goal here is not to write everything with pointers and Span. But, we return to the “expert” story again – you can still keep in mind performance, good and bad practices, be aware of abstraction leaks. And have “entry points” how to fix, trace, debug, measure… You can be an expert!
  • library author perspective – well, you don’t know your customers. It just should be fast. And performance, among features, documentation, clean design, becomes one of the distinguishing factors when we choose this library or another. There is no sky limit here. The goal is to write everything with pointers and Span 😉 (yes, joke!). What’s I’m trying to say is that this perspective favors writing performance- and memory-aware code a little more.

Bonus question to you: Do you want to only consume .NET libraries, EF Core, ASP.NET Core, Unity, Xamarin, RavenDB, … or produce them? For money? Guess what you need to have a chance for doing that. Yes, you have to scratch your comfortable abstractions off the surface. “The only way to deal with the leaks competently is to learn about how the abstractions work and what they are abstracting as Joel Spolsky said in the article cited above. The whole Mechanical Sympathy movement is about that. Understand one or two layers below the one you use.

Summarizing, and answering the title question, here is my pragmatic approach to .NET memory management – split it into levels and decide which level suits you the most:

  • Level 0 – I really don’t care, I just want to make things done.
  • Level 1 – Keep in mind some knowledge of abstractions, some basic sanity checks like: use struct here, don’t use LINQ there, set Capacity of the List, know what are the consequences of allocating a lot in LOH (and what LOH is in the first place), and so on and so forth. Just clean code for performance. Explaining that you should be there is just like explaining you should write clean code and tests. Or wash hands before you eat. This allows you to feel comfortable and “expertised” in “80%” zone.
  • Level 2 – Be more interested. Know how to measure and diagnose if something bad happens. Have a good toolbox for measuring and troubleshooting. Have some more knowledge of abstractions that may leak. Move to the “20%” zone, become an expert. Get better salary, seek for interesting projects (and they will seek you!).
  • Level 3: Optimize and be really memory-aware like a crazy. Use advanced C# tricks, refs, Span, stackalloc. Get some internals knowledge. Sell your unique knowledge for serious money.

I’m personally not paralized by the high-perf code too. I start from working prototype and only then I measure and optimize, if needed at all. But having those sanity checks allows me to avoid stupid mistakes. It is just a “gut feeling” you may get when moving to the higher levels. BTW, this all applies to everything we use – architecture, async/await, ORM, .NET runtime itself, …

This is where the most of the story ends for you and me. But there’s more a little more – a broader, company perspective. When talking about taking care of .NET memory and performance, I often meet those tree mantras:

  • #1 “Infra will take it” – I agree, sometimes it is just cheaper to put more $$$ on Azure instead of paying a dev. Especially, if you are a startup. But this approach should have some end, I strongly believe. There is “Software disenchantment” article from 2018, which received some attention in my circles recently, with which I agree SO MUCH“Everything is unbearably slow”, and inefficient. I highly recommend reading it as a follow-up to this post! And well, throwing money on hardware to excuse our laziness… I’d really love to see start seeing some “Ecological Sympathy” among companies. Yes, consuming more CPU/RAM on a phone or in cloud in the end translates to natural resources drainage.
  • #2 “We have C++ for that” – Yes… but does .NET-based company really want to hire a single C/C++ developer, install the whole new build ecosystem into the pipeline… for some critical 3% part of it being written in C++, while C# allows to do the same with just a little involvement of learning?
  • #3 “We just don’t care” – Well… Milliseconds Make Millions. There are so many reports showing clearly how directly slowness of an app translates to worse conversions, income, retention, however you call it.

But again, this is all more like company perspective. What does this mean for you? Just sell it, become an expert – whether it is architecture scalability & performance. Become Software Craftsmen. It waits for you!

HOW you can learn? There’s a lot of free stuff like .NET Memory Performance Analysis document by Maoni Stephens, Garbage Collection Design from “The Book of the Runtime” or my .NET GC Tips & Tricks and .NET GC Internals series on YT. There are conferences and webinars. And if you want to pay, there’s my book and my recently announced .NET Memory Course course which is just for that.

PS. Bonus sidenote for people seeing some small optimizations and immediately misquoting Donald Knuth saying “premature optimization is the root of all evil”. The whole context of this quote, coming from 1974 “Structured Programming with goto Statements” paper, is: “We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%. A good programmer will not be lulled into complacency by such reasoning, he will be wise to look carefully at the critical code; but only after that code has been identified.”


What do you know about .NET memory management? Should you care at all? Yes, it is all managed and automatic and the Garbage Collector takes care of everything. That’s a great achievement of managed runtimes in general – they provide this super nice abstraction of memory that is just there and we do not need to think about it at all, right?

Well, yes and no. For sure you may for years develop business applications earning money and do not touch a topic of .NET memory management at all. I’ve been there too. But, there is always more. There is always some edge case, some scalability problem, a memory leak or just not efficient resources utilization (wasting money💸). I’m not here today to convince you to that, tough. There will be time for this 🙂

Today I just wanted to invite you to my new initiative – a small quiz about .NET memory management. 32 questions that may, or may not, shed some light on you in the context of this topic:

👉 Take a quiz 👈

Share your result, elaborate about questions! And as you see at the end, you can subscribe to the newsletter where I’ll be providing explanations of correct answers for every question.

And yes, this is a beginning of a bigger initiative https://dotnetmemoryexpert.com – more about it soon. In general, more and more GC- and memory-related content is coming!😍



Hi and welcome to the third episode of the .NET GC internals! Yesterday is was again 1.5h of talking about the Mark phase, this time in its Concurrent flavour. Most of the time I’ve described the solution and implementation of it to two problems:

  • Problem #1 – how to mark an object while being used? – in non-Concurrent Mark phase MethodTable pointers is used for this. But now, while the application is running and may access this pointer, it is not the best place ever 🙂
  • Problem #2 – how to get a consistent view while references are changing? – even more difficult problem, as the GC tries to discovers what is reachable while references between objects are constantly changed by the application


Enjoy watching the recording on YouTube and if you have any questions, do not hesitate to ask!

As usual, you can get the slides from our goodies page.

And do not forget to join Wednesday, February 10, 7PM CET – this time I’ll cover Plan phase, describing such internal stuff like “plugs”, “gaps”, “brick tables” and more!

Hi and welcome to the second episode of the .NET GC internals! Yesterday is was 1.5h of talking about the (non-concurrent) Mark phase. The one responsible for discovering which object are “reachable” and which may be garbage collected. I’ve covered topics like object graph traversal algorithm, the pinning and marking flag, the mark stack and mark list data structures. And obviously, some deep dive into the gc.cpp at the end.


Enjoy watching the recording on YouTube and if you have any questions, do not hesitate to ask!Continue reading

I’ve decided to make a series of at least 8 free weekly-based webinars about in-depth implementation details of the .NET GC and… I’m super happy with it! Why the idea? Many my other activities are about more practical “.NET memory management”, like my book or workshops/trainings/consultancy I gave. But during all this practical-oriented events there is always not enough time to explain in details how .NET GC is implemented. Obviously, I always explain some concepts and algorithms, to the level that helps in understanding the whole concept. But not with the level of details that I am satisfied.

Hence the idea – make a separate content that will be just as deep as I like 🙂 So, I will cover details on the level of bits, bytes and source code, not only on the level of the overall algorithm description.

The first episode was yesterday, feel invited to watch:

Continue reading


In the upcoming .NET 5 a very interesting change is added to the GC – a dedicated Pinned Object Heap, a very new type of the managed heap segment (as we have Small and Large Object Heaps so far). Pinning has its own costs, because it introduces fragmentation (and in general complicates object compaction a lot). We are used to have some good practices about it, like “pin only for…:

  • a very short time” so, the GC will not bother – to reduce probability that the GC happens while many objects were pinned. That’s a scenario to use fixed keyword, which is in fact only a very lightweight way of flagging particular local variable as a pinned reference. As long as GC does not happen, there is no additional overhead.
  • a very long time”, so the GC will promote those objects to generation 2 – as gen2 GCs should be not so common, the impact will be minimized also. That’s a scenario to use GCHandle of type Pinned, which is a little bigger overhead because we need to allocate/free handle.

However, even if applied, those rules will produce some fragmentation, depending how much you pin, for how long, what’s the resulting layout of the pinned objects in memory and many other, intermittent conditions.

So, in the end, it would be perfect just to get rid of pinned objects and move them to a different place than SOH/LOH. This separate place would be simply ignored, by the GC design, when considering heap compaction so we will get pinning behaviour out of the box.Continue reading


In the previous post, I’ve announced that I’m working on a card game for .NET developers. In this post, I would like to make yet another one exciting announcement – OutOfMemory! game will be Kickstarted and… even more – it will be not alone! As around at the same time as I planned, another IT-related card game was going to be announced, we decided to join forces and benefit from such synergy, instead of stepping on each other toes. This decision was quite obvious – both we are developers, both we are from Poland and both we are planning to offer IT-related card game 🙂

So, I am pleased to announce that since today we are joining our design, marketing, and social media forces, which eventually will result in a joined Kickstarter campaign, about two game cards at once:

  • OutOfMemory! game for .NET developers (and I’m strongly considering other languages/ecosystems as an option) – in short, a game about building an application from features, with a strong emphasis on their performance and memory consumption
  • IT Startup game – about building IT company, by hiring developers and taking care of their burnout. This project has been already successfully crowdfunded here in Poland and now its author – Mateusz Kupilas – wants to expand into the international market.

With our joined social media channels and Mateusz experience of selling over 2500 IT Startup games, we believe everyone will benefit – and mostly, potential players!

As a project supporter, you will have an option to support one of those games or both (with a proper discount, of course!). We even considered designing both games in a way allowing to combine them into one, if one wishes. But this idea is currently postponed.

When both games will show up on Kickstarter? Not in the upcoming months, for sure. Most probably, at the beginning of February 2020. Since then there will be a lot of time to polish game design and build some community around prototypes.

If you want to learn more about IT Startup, please feel invited to visit its dedicated page at http://playitstartup.com/, or follow its social media channels on Facebook It Startup – The Card Game page or on Twitter @playitstartup. Mateusz writes also about our cooperation on his blog (in Polish) – https://www.javadevmatt.pl/lacze-sily-z-konradem/


During our trip around managed pointers and structs, we get the last topic to discuss – readonly semantics. Thus, we touch today topics like readonly structs and readonly paremeters.

Readonly ref variables

Ref types are quite powerful, because we may change its target. Thus, readonly refs were introduced in C# 7.2 that controls the ability to mutate the storage of a ref variable.
Please note a subtle difference in such context between a managed pointer to a value type versus a reference type:

  • for value type target – it guarantees that the value will not be modified. As the value here is the whole object (memory region), in other words, it guarantees that all fields will not be changed.
  • for reference type target – it guarantees that the reference value will not be changed. As the value here is the reference itself (pointing to another object), it guarantees that we will not change it to point to another object. But we can still modify the properties of the referenced object.

Let’s use an example returning a readonly ref:

BookCollection may illustrate the difference between readonly ref in case of both value type and reference type.Continue reading

Among many things that are coming with the upcoming C# 8.0, one perfectly fits the topic of ref structs I’ve raised in my previous postdisposable ref structs.

As one of the blog posts announcing C# 8.0 changes (in Visual Studio 2019 Preview 2) mentions:

“Ref structs were introduced in C# 7.2, and this is not the place to reiterate their usefulness, but in return they come with some severe limitations, such as not being able to implement interfaces. Ref structs can now be disposable without implementing the IDisposable interface, simply by having a Dispose method in them.”

Continue reading

Disclaimer – this article consists of fragments of my book, adapted and re-edited considerably to be presented in the form of an independent whole post.

As already explained in the previous article, managed pointers have their well-justified limitations – especially in that they are not allowed to appear on the Managed Heap (as a field of reference type or just by boxing). However, for some scenarios, it would be really nice to have a type that contains a managed pointer. The main motivation behind such type is Span<T> – which should be able to represent references “inside” objects (interior pointers), stack address or even unmanaged memory.

Ref struct (byref-like type)

Such type should have similar limitations as the managed pointer itself (to not break limitations of the contained managed pointer). Thus, those kinds of types are commonly called byref-like types (as the other name of the managed pointer is simply byref). The most important limitation of such type should be an impossibility to have heap-allocated instances. Thus the direction seems obvious – structs with some additional restrictions should be introduced. Regular structs by default are stack-allocated but may be heap-allocated in various scenarios, like boxing (for example because of casting to an interface).Continue reading