Skip to content

ddrdoubled/resharper-heapview

 
 

Repository files navigation

HeapAllocationViewer for Rider and ReSharper

Rider ReSharper

This plugin 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.

Example

Features

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 }
}
  • It can visualize some hidden allocations happening in C#, including:
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
  }
}
  • It can detect delegate instances allocation, ignoring cached delegates:
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
  }
}
  • It can detect closure ("display classes") creation points:
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)));
    }
  }
}

Notes

  • Please, avoid premature optimizations. Use this tool with care, only when it matters to reduce allocations count;
  • You can change default colors of highlightings in Visual Studio settings: go Tools - Settings - Fonts and colors and check colors for items "ReSharper HeapView Boxing" and "ReSharper HeapView Allocation";
  • You can change highlighting severity or search for all issues in project/solution as usual - via Alt+Enter menu over highlighting;
  • This plugin highly relies on Microsoft's implementation of C# compiler shipping with VS, it may produce false positives for other C# implementations like Mono C# compiler;
  • Plugin's changelog is here.

About

ReSharper Heap Allocations Viewer plugin

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C# 95.2%
  • PowerShell 4.2%
  • Kotlin 0.6%