はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Rider】RiderにHeap Allocations Viewerを導入してヒープアロケーションを可視化する(Unityでもオススメ)

はじめに

今回はHeap Allocations Viewerについて取り上げたいと思います。

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.

// DeepL翻訳
このプラグインは、C#のコードを静的に解析し、ローカルオブジェクトの割り当てが行われていることをすべて発見します。

C#プログラムのホットパスでのヒープ割り当てを減らすために使用することができます。

GitHub - controlflow/resharper-heapview: ReSharper Heap Allocations Viewer plugin

動作している様子

インストール

メニューバーよりFile -> Settings...を選択。

Settings Window

サイドバーよりPluginsを選択し、検索ボックスにHeap Allocations Viewerと入力し、インストールを行います。

インストール

インストールできるとRestart IDEという表示が出てくるので、再起動すれば完了です。

使い方

Heap Allcationが発生するコードを検出し、可視化してくれます。

可視化している様子

Boxingの例

internal struct Boxing
{
    private enum E {A, B, C}

    private void Hoge()
    {
        // Boxing allocation: conversion from 'int' to 'object' requires boxing of the value type
        object obj = 42;
            
        // Boxing allocation: conversion from 'char' to 'object' requires boxing of the value type
        string path = "a" + '/' + obj;

        // Boxing allocation: inherited 'ValueType.GetHashCode()' virtual method invocation over the value type instance
        int code = this.GetHashCode();
            
        // Boxing allocation: inherited 'Enum.ToString()' virtual method invocation over the value type instance
        string caseA = E.A.ToString();

        // Boxing allocation: conversion from 'E' to 'IComparable' requires boxing of the value type
        IComparable comparable = E.A;

        // Boxing allocation: conversion of value type 'Boxing' instance method to 'Action' delegate type
        // Delegate allocation: new 'Action' instance creation
        Action action = this.Hoge;
    }
}

Object allocationの例

void Method(params string[] args)
{
    // Object allocation: string concatenation
    string c = args[0] + "/";
        
    // Object allocation: new 'string[]' array instance creation for params parameter 'args'
    Method("abc", "cdf");
}

private void N(List<string> xs)
{
    // No Allocations
    foreach (var s in xs) Console.WriteLine(s);

    // Possible object allocation: new 'IEnumerator<string>' instance creation on 'GetEnumerator()' call (except when it's cached by the implementation)
    IEnumerable<string> ys = xs;
    foreach (var s in ys) Console.WriteLine(s);
}

Delegate allocationの例

private static void M(string s)
{
    // Delegate allocation: new 'Action' instance creation Capture of parameter 's'
    Action closure = () => M(s);
}

private void M<T>()
{
    // Delegate allocation: new 'Action' instance creation Capture of 'this' reference
    Action closure = () => M<T>();
}

Closure allocationの例

class Closures {
    IEnumerable<string> StupidExample(string str)
    {
        // Closure allocation: capture of 'value' variable and containing closure ('str')
        int value = str.Count(x => x == '_');

        // Delegate allocation: new 'Func<int,string>' instance creation Capture of parameter 'str' and variable 'value'
        return Enumerable
            .Range(0, str.Length)
            .Select(count => str.Substring(Math.Max(value, count)));
    }
}