This plugins statically analyzes C# code to find all local object allocations happening.
It can be used to reduce number of heap allocations in hot paths of your C# program.
2016.2
, 2016.3
and 2017.1
;8.x
, 9.x
, 10.0
and 2016.1
are no longer supported, check extension manager for latest versions;struct Boxing { void M(string a) { object obj = 42; // implicit conversion Int32 ~> Object string path = a + '/' + obj; // implicit conversion Char ~> Object int code = this.GetHashCode(); // non-overriden virtual method call on struct string caseA = E.A.ToString(); // the same, virtual call IComparable comparable = E.A; // valuetype conversion to interface type Action<string> action = this.M; // delegate from value type method Type type = this.GetType(); // GetType() call is always virtual } enum E { A, B, C } }
class HeapAllocations { List<int> _xs = new List<int>(); // explicit object creation expressions int[] _ys = {1, 2, 3}; // allocation via array initializer syntax void M(params string[] args) { string c = args[0] + "/"; // string concatenation M("abc", "def"); // parameters array allocation M(); // the same, hidden 'new string[0]' var xs = Enumerable.Range(0,1); // iterator method call var ys = from x in xs let y = x + 1 // anonymous type creation for 'let' select x + y; } void N(List<string> xs) { foreach (var s in xs) F(s); // no allocations, value type enumerator IEnumerable<string> ys = xs; foreach (var s in ys) F(s); // IEnumerator allocation in foreach } }
class Delegates { static void M(string s) { Action<string> method = M; // non-cached delegate from method group Action lambda = () => M("a"); // cached delegate from static lambda Action closure = () => M(s); // non-cached lambda with closure 's' } void M<T>() { Action generic = () => { }; // non-cached, lambda in generic method Action closure = () => M<T>(); // non-cached, captures 'this' to closure } }
class Closures { IEnumerable<string> StupidExample(string str) { // <= hidden closure class allocation happens here if (str == null) return Enumerable.Empty<string>(); if (str.Length == 0) { return Enumerable.Empty<string>(); } else { // <= second hidden closure allocation (nested closure) int value = str.Count(x => x == '_'); return Enumerable .Range(0, str.Length) .Select(count => // delegate instance allocation str.Substring(Math.Max(value, count))); } } }
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4