LOOK MOMMY, NO GC!
DINA GOLDSHTEIN,
@DINAGOZIL
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
AGENDA
▸ Motivation
▸ Identifying memory traffic problems
▸ Specific code patterns
▸ General tips and tricks
2
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
IT’S NOT THAT SIMPLE
▸ Memory allocations are cheap
▸ But not free
▸ And have side effects
▸ Don’t forget to think about the memory
3
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
THIS ISN’T JUST THEORY
4
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
THIS ISN’T JUST THEORY
5
IDENTIFICATION
STEP I
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
PERFORMANCE COUNTERS
▸ Provide numeric performance information about the system
▸ Located in different areas in the system - disk, .NET, networking, OS objects
▸ Available on-demand using built-in tools like perfmon and typeperf
▸ Can write your own but that’s not the topic of our talk…
7
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
PERFMON
8
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
DIVE DEEPER WITH EVENT TRACING FOR WINDOWS
▸ High-speed logging framework supporting more than 100K structured
messages per second
▸ .NET, drivers, services, third party components
▸ Can be turned on on-demand while running
▸ Very small overhead
▸ Can write your own but that’s not the topic of our talk…
9
PERFVIEW
DEMO
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
STATIC CODE ANALYSIS
▸ Can detect code issues while coding without running the application
▸ Usually based on pattern-detection
▸ Undisposed IDisposable-s
▸ Inefficient String concatenations
▸ Wrong number of “dynamic” parameters
▸ ReSharper, Visual Studio, and more
11
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
TIPS IN VS
12
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
DYNAMIC MEMORY PROFILING
▸ Dynamic analysis can help uncover more subtle scenarios
▸ Can collect temporal information
▸ Managed and unmanaged memory leaks
▸ Lots of commercial tools available: .NET Memory Profiler, ANTS, dotMemory…
13
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
.NET MEMORY PROFILER AND MEMORY LEAKS
14
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
WHO’S HOLDING MY OBJECTS?
15
AVOIDANCE
STEP II
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
GARBAGE, GARBAGE EVERYWHERE
17
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
STRUCTS, COMPARISONS AND WHAT’S BETWEEN THEM
▸ We have a data structure containing a single int value
▸ How long does it take to search an element in a list of such data structures?
▸ Different implementations
▸ Default comparison
▸ Override Equals
▸ Implement IEquatable
18
SEARCHING
DEMO
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
RESULTS
20
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
HOW DOES SEARCHING WORK?
21
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
HOW DOES COMPARING WORK?
22
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
WHAT’S THE DIFFERENCE?
23
…
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
OBJECT EQUALITY COMPARER
24
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
GENERIC EQUALITY COMPARER
25
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
WHAT’S TAKING ALL THE TIME?
26
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
REFLECTION IS EXPENSIVE
27
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
LAMBDAS AND CLOSURES
28
CAPTURING
DEMO
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
THE RESULTS
30
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
IT’S ALL ABOUT THE ALLOCATIONS
31
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
UNDER THE HOOD - AN ALLOCATION FOR EACH CAPTURE
32
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
UNDER THE HOOD - NO CAPTURING; HENCE, NO ALLOCATION!
33
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
UNDER THE HOOD - NO DATA; HENCE, NO ALLOCATION!
34
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
UNDER THE HOOD - BUG 🐞
35
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
THE RESULTS
36
LINQ
DEMO
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
RESULTS
38
DILIGENCE
STEP III
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
DON’T CALL GC.COLLECT()
▸ You have a large heap. Don’t make it worse by frequent calls to full GC which is
going to take a long time.
▸ Instead, use what we learned to reduce memory usage
▸ And don’t forget to remove debugging code from production
40
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
THIS IS NOT A DRILL
41
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
FAMOUS LAST WORDS
42
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
AN (UN)FORTUNATE COINCIDENCE
43
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
PREFER VALUE TYPES
▸ Value types (structs) have a compact memory layout, and can be embedded in
their parent object, making cache’s life easier and generally reducing footprint
44
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
BASED ON A REAL STORY
45
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
POOL, BUFFER AND REUSE EXPENSIVE OBJECTS
▸ Pool expensive or large objects
instead of returning them to GC
▸ Many OSS pools out there
▸ For large arrays (e.g. byte[]) may use
System.Buffers
▸ A large preallocated buffer which
is sliced into small parts
46
https://github.com/dotnet/corefx/blob/master/src/System.Buffers/tests/ArrayPool/UnitTests.cs
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
HARD TO WATCH
47
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
AVOID FINALIZATION
▸ Finalizers run at some point after the object is no longer referenced by the
application (non-deterministic)
▸ Finalizers run on a separate thread and create potential concurrency issues
▸ Finalization prolongs object lifetime and can create leaks if finalizers don’t
complete quickly enough
▸ Better to use deterministic resource management (IDisposable)
48
.NET SUMMIT BELARUS 2017 #DOTNETSUMMITBY | @DINAGOZIL
SUMMARY
▸ Although a single memory allocation is extremely fast, it adds up
▸ All based on real questions, stories and bugs
▸ Don’t overcomplicate where it’s not needed
▸ Measure
▸ And optimize…
▸ DIY: https://github.com/dinazil/look-mommy-no-gc
49
THANK YOU!
DINA GOLDSHTEIN,
@DINAGOZIL

Look Mommy, no GC! (.NET Summit 2017)

  • 1.
    LOOK MOMMY, NOGC! DINA GOLDSHTEIN, @DINAGOZIL
  • 2.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL AGENDA ▸ Motivation ▸ Identifying memory traffic problems ▸ Specific code patterns ▸ General tips and tricks 2
  • 3.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL IT’S NOT THAT SIMPLE ▸ Memory allocations are cheap ▸ But not free ▸ And have side effects ▸ Don’t forget to think about the memory 3
  • 4.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL THIS ISN’T JUST THEORY 4
  • 5.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL THIS ISN’T JUST THEORY 5
  • 6.
  • 7.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL PERFORMANCE COUNTERS ▸ Provide numeric performance information about the system ▸ Located in different areas in the system - disk, .NET, networking, OS objects ▸ Available on-demand using built-in tools like perfmon and typeperf ▸ Can write your own but that’s not the topic of our talk… 7
  • 8.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL PERFMON 8
  • 9.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL DIVE DEEPER WITH EVENT TRACING FOR WINDOWS ▸ High-speed logging framework supporting more than 100K structured messages per second ▸ .NET, drivers, services, third party components ▸ Can be turned on on-demand while running ▸ Very small overhead ▸ Can write your own but that’s not the topic of our talk… 9
  • 10.
  • 11.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL STATIC CODE ANALYSIS ▸ Can detect code issues while coding without running the application ▸ Usually based on pattern-detection ▸ Undisposed IDisposable-s ▸ Inefficient String concatenations ▸ Wrong number of “dynamic” parameters ▸ ReSharper, Visual Studio, and more 11
  • 12.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL TIPS IN VS 12
  • 13.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL DYNAMIC MEMORY PROFILING ▸ Dynamic analysis can help uncover more subtle scenarios ▸ Can collect temporal information ▸ Managed and unmanaged memory leaks ▸ Lots of commercial tools available: .NET Memory Profiler, ANTS, dotMemory… 13
  • 14.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL .NET MEMORY PROFILER AND MEMORY LEAKS 14
  • 15.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL WHO’S HOLDING MY OBJECTS? 15
  • 16.
  • 17.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL GARBAGE, GARBAGE EVERYWHERE 17
  • 18.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL STRUCTS, COMPARISONS AND WHAT’S BETWEEN THEM ▸ We have a data structure containing a single int value ▸ How long does it take to search an element in a list of such data structures? ▸ Different implementations ▸ Default comparison ▸ Override Equals ▸ Implement IEquatable 18
  • 19.
  • 20.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL RESULTS 20
  • 21.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL HOW DOES SEARCHING WORK? 21
  • 22.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL HOW DOES COMPARING WORK? 22
  • 23.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL WHAT’S THE DIFFERENCE? 23 …
  • 24.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL OBJECT EQUALITY COMPARER 24
  • 25.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL GENERIC EQUALITY COMPARER 25
  • 26.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL WHAT’S TAKING ALL THE TIME? 26
  • 27.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL REFLECTION IS EXPENSIVE 27
  • 28.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL LAMBDAS AND CLOSURES 28
  • 29.
  • 30.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL THE RESULTS 30
  • 31.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL IT’S ALL ABOUT THE ALLOCATIONS 31
  • 32.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL UNDER THE HOOD - AN ALLOCATION FOR EACH CAPTURE 32
  • 33.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL UNDER THE HOOD - NO CAPTURING; HENCE, NO ALLOCATION! 33
  • 34.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL UNDER THE HOOD - NO DATA; HENCE, NO ALLOCATION! 34
  • 35.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL UNDER THE HOOD - BUG 🐞 35
  • 36.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL THE RESULTS 36
  • 37.
  • 38.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL RESULTS 38
  • 39.
  • 40.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL DON’T CALL GC.COLLECT() ▸ You have a large heap. Don’t make it worse by frequent calls to full GC which is going to take a long time. ▸ Instead, use what we learned to reduce memory usage ▸ And don’t forget to remove debugging code from production 40
  • 41.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL THIS IS NOT A DRILL 41
  • 42.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL FAMOUS LAST WORDS 42
  • 43.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL AN (UN)FORTUNATE COINCIDENCE 43
  • 44.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL PREFER VALUE TYPES ▸ Value types (structs) have a compact memory layout, and can be embedded in their parent object, making cache’s life easier and generally reducing footprint 44
  • 45.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL BASED ON A REAL STORY 45
  • 46.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL POOL, BUFFER AND REUSE EXPENSIVE OBJECTS ▸ Pool expensive or large objects instead of returning them to GC ▸ Many OSS pools out there ▸ For large arrays (e.g. byte[]) may use System.Buffers ▸ A large preallocated buffer which is sliced into small parts 46 https://github.com/dotnet/corefx/blob/master/src/System.Buffers/tests/ArrayPool/UnitTests.cs
  • 47.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL HARD TO WATCH 47
  • 48.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL AVOID FINALIZATION ▸ Finalizers run at some point after the object is no longer referenced by the application (non-deterministic) ▸ Finalizers run on a separate thread and create potential concurrency issues ▸ Finalization prolongs object lifetime and can create leaks if finalizers don’t complete quickly enough ▸ Better to use deterministic resource management (IDisposable) 48
  • 49.
    .NET SUMMIT BELARUS2017 #DOTNETSUMMITBY | @DINAGOZIL SUMMARY ▸ Although a single memory allocation is extremely fast, it adds up ▸ All based on real questions, stories and bugs ▸ Don’t overcomplicate where it’s not needed ▸ Measure ▸ And optimize… ▸ DIY: https://github.com/dinazil/look-mommy-no-gc 49
  • 50.