exploring .net memory management (isense)

38
Exploring .NET memory management A trip down memory lane Maarten Balliauw @ maartenballiauw

Upload: maarten-balliauw

Post on 22-Jan-2018

160 views

Category:

Technology


2 download

TRANSCRIPT

Exploring .NET memory managementA trip down memory laneMaarten Balliauw@maartenballiauw

Agenda

Garbage Collector

Helping the GC

Allocations & hidden allocations

Strings

Exploring the heap

Garbage Collector

Memory management and GC

Virtually unlimited memory for our applications

Big chunk of memory pre-allocated

Runtime manages allocation in that chunk

Garbage Collector (GC) reclaims unused memory, making it available again

.NET memory management 101

Memory allocation

Objects allocated in “managed heap” (big chunk of memory)

Allocating memory is fast, it’s just adding a pointer

Some unmanaged memory is also consumed (not GC-ed).NET CLR, Dynamic libraries, Graphics buffer, …

Memory release or “Garbage Collection” (GC)

Generations

Large Object Heap

.NET memory management 101

Memory allocation

Memory release or “Garbage Collection” (GC)

GC releases objects no longer in use by examining application roots

GC builds a graph of all the objects that are reachable from these roots

Object unreachable? Remove object, release memory, compact heap

Takes time to scan all objects!

Generations

Large Object Heap

.NET memory management 101

Memory allocation

Memory release or “Garbage Collection” (GC)

Generations

Large Object Heap

Generation 0 Generation 1 Generation 2

Short-lived objects (e.g. Local

variables)

In-between objects Long-lived objects (e.g. App’s

main form)

.NET memory management 101

Memory allocation

Memory release or “Garbage Collection” (GC)

Generations

Large Object Heap (LOH)

Special segment for large objects (>85KB)

Collected only during full garbage collection

Not compacted (by default)

Fragmentation can cause OutOfMemoryException

The .NET garbage collector

When does it run? Vague… But usually:Out of memory condition – when the system fails to allocate or re-allocate memoryAfter some significant allocation – if X memory is allocated since previous GCFailure of allocating some native resources – internal to .NETProfiler – when triggered from profiler APIForced – when calling methods on System.GCApplication moves to background

GC is not guaranteed to runhttp://blogs.msdn.com/b/oldnewthing/archive/2010/08/09/10047586.aspx

http://blogs.msdn.com/b/abhinaba/archive/2008/04/29/when-does-the-net-compact-framework-garbage-collector-run.aspx

The .NET garbage collector

Runs very often for gen0Short-lived objects, few references, fast to clean

Local variableWeb request/response

Higher generationUsually more references, slower to clean

GC pauses the running application to do its thingUsually short, except when not…

Background GC (enabled by default)Concurrent with application threadsMay still introduce short locks/pauses, usually just for one thread

Helping the GC, avoid pauses

Optimize allocations (but don’t do premature optimization – measure!)

Don’t allocate at all

Make use of IDisposable / using statement

Clean up references, giving the GC an easy job

Finalizers

Beware! Moved to finalizer queue -> always gen++

Weak references

Allow the GC to collect these objects, no need for checks

Helping the GCDEMO

https://github.com/maartenba/memory-demos

Allocations

When is memory allocated?

Not for value types (int, bool, struct, decimal, enum, float, byte, long, …)

Allocated on stack, not on heap

Not managed by garbage collector

For reference types

When you new

When you ""

Hidden allocations!

Boxing!Put and int in a box

Take an int out of a box

Lambda’s/closuresAllocate compiler-generated DisplayClass to capture state

Params arrays

And more!int i = 42;

// boxing - wraps the value type in an "object box"// (allocating a System.Object)object o = i;

// unboxing - unpacking the "object box" into an int again// (CPU effort to unwrap)int j = (int)o;

How to find them?

Experience

Intermediate Language (IL)

Profiler

“Heap allocations viewer”

ReSharper Heap Allocations Viewer plugin

Roslyn’s Heap Allocation Analyzer

Don’t do premature optimization – measure!

Hidden allocationsDEMO

https://github.com/maartenba/memory-demos

ReSharper Heap Allocations Viewer plugin

Roslyn’s Heap Allocation Analyzer

Don’t optimize what should not be optimized.

Measure!

We know when allocations are done...

...but perhaps these don’t matter.

Measure!

How frequently are we allocating?

How frequently are we collecting?

What generation do we end up on?

Are our allocations introducing pauses?

www.jetbrains.com/dotmemory (and www.jetbrains.com/dottrace)

Garbage Collector & Allocations

GC is optimized for high memory traffic in short-lived objects

Use that knowledge! Don’t fear allocations!

Don’t optimize what should not be optimized…

GC is the concept that makes .NET / C# tick – use it!

Know when allocations happen

GC is awesome

Gen2 collection that stop the world not so much…

Measure!

Strings

Strings are objects

.NET tries to make them look like a value type, but they are a reference type

Read-only collection of char

Length property

A bunch of operator overloading

Allocated on the managed heap

var a = new string('-', 25);

var b = "Hello, World!";

var c = httpClient.GetStringAsync("http://blog.maartenballiauw.be");

Measuring string allocationsDEMO

https://github.com/maartenba/memory-demos

String duplicates

Any .NET application has them (System.Globalization duplicates quite a few)

Are they bad?

.NET GC is fast for short-lived objects, so meh.

Don’t waste memory with string duplicates on gen2(but: it’s okay to have strings there)

String literals

Are all strings on the heap? Are all strings duplicated?

var a = "Hello, World!";var b = "Hello, World!";

Console.WriteLine(a == b);Console.WriteLine(Object.ReferenceEquals(a, b));

Prints true twice. So “Hello World” only in memory once?

Portable Executable (PE) #UserStrings

DEMO

https://github.com/maartenba/memory-demos

String literals in #US

Compile-time optimization

Store literals only once in PE header metadata stream ECMA-335 standard, section II.24.2.4

Reference literals (IL: ldstr)

var a = Console.ReadLine();var b = Console.ReadLine();

Console.WriteLine(a == b);Console.WriteLine(Object.ReferenceEquals(a, b));

String interning to the rescue!

String interning

Store (and read) strings from the intern pool

Simply call String.Intern when “allocating” or reading the string

Scans intern pool and returns reference

var url = string.Intern("http://blog.maartenballiauw.be");

var stringList = new List<string>();for (int i = 0; i < 1000000; i++){

stringList.Add(url);}

String interning caveats

Why are not all strings interned by default?

CPU vs. memory

Not on the heap but on intern pool

No GC on intern pool – all strings in memory for AppDomain lifetime!

Rule of thumb

Lot of long-lived, few unique -> interning good

Lot of long-lived, many unique -> no benefit, memory growth

Lot of short-lived -> trust the GC

Measure!

Exploring the heapfor fun and profit

Memory layout

Pointer to an “instance”

Instance:Pointer to RTTIProperty1Property2…

RTTI:Property types and namesMethods…

Theory is nice...

Microsoft.Diagnostics.Runtime (ClrMD)

“ClrMD is a set of advanced APIs for programmatically inspecting a crash dump of a .NET program much in the same way that the SOS Debugging Extensions (SOS) do. This allows you to write automated crash analysis for your applications as well as automate many common debugger tasks. In addition to reading crash dumps ClrMD also allows supports attaching to live processes.”

Maarten’s definition: “LINQ-to-heap”

ClrMD introductionDEMO

https://github.com/maartenba/memory-demos

String duplicatesDEMO

https://github.com/maartenba/memory-demos

“Path to root”(why is my object kept in memory)DEMO

https://github.com/maartenba/memory-demos

Conclusion

Conclusion

Garbage Collector (GC) optimized for high memory traffic + short-lived objects

Don’t fear allocations! But beware of gen2 “stop the world”

String interning when lot of long-lived, few unique

Don’t optimize what should not be optimized…

Measure!Using a profiler/memory analysis tool

ClrMD to automate inspections

dotMemory Unit, Benchmark.NET, … to profile unit tests

Blog series: https://blog.maartenballiauw.be

Thank you!http://blog.maartenballiauw.be

@maartenballiauw