Неожиданное поведение gc alloc в connectedList.find () - PullRequest
3 голосов
/ 04 октября 2019

Поскольку все мы знаем, что если мы сравним переменную типа значения с нулем, это приведет к тому, что GC выделит причину для бокса:

{
    public class TestGeneric<T>{

        public static bool TestGC(T key)
        {
            return key == null;
        }
    }
    TestGeneric<int>.TestGC(10);
}

Однако я обнаружил, что метод Find (T value) метода LinkedList(System.Collections.Generic) использовал тот же код, что и

public LinkedListNode<T> Find(T value)
{
    if (value != null)
    {
        //....
    }
}

Но вызов, подобный

//LinkedList<int> list;
list.Find(10);

, НЕ приведет к выделению GC.

Я действительно смущен этим. У кого-нибудь есть идея? Пожалуйста, помогите. Большое спасибо.

====================

Тестовая среда: Unity 2018, Unity Profiler (Deep ProfileВключить) .Net Версия: 4.0

Вот мой тестовый код.

public class TestGeneric<T> {

    public static bool TestGC(T key)
    {
        return key == null;
    }
}

public class LinkedListTest : MonoBehaviour
{
    LinkedList<int> list = new LinkedList<int>();
    void Start()
    {
        for (int i = 0; i < 10; ++i)
        {
            list.AddLast(i);
        }
    }
    void Update()
    {
        for (int i = 0; i < 10; ++i)
        {
            TestGeneric<int>.TestGC(10);
        }
        for (int i = 0; i < 10; ++i)
        {
            list.Find(100);
        }
    }
}

Профилировщик единства показывает

Метод TestGC вызвал200Byte GC Alloc на кадр.

list.Find метод вызвал 0Byte GC Alloc на кадр.

1 Ответ

0 голосов
/ 04 октября 2019

Кажется, что LinkedList<T>.Find (https://referencesource.microsoft.com/#System/compmod/system/collections/generic/linkedlist.cs,74e4e6394382badc,references)

использует EqualityComparer<T> для сравнения значений, что, в свою очередь, использует IEquatable<T>.Equals(T) (https://docs.microsoft.com/en-us/dotnet/api/system.iequatable-1.equals?view=netframework-4.8)

, что

Когда вызывается метод Equals, а другой аргумент является строго типизированным объектом типа T. (Если other не относится к типу T, вызывается базовый метод Object.Equals (Object). Из двух методов:IEquatable.Equals предлагает немного лучшую производительность.)

Поскольку вы сравниваете int и они того же типа, бокс не происходит, так как Object.Equals не вызывается.

...