首页 > 解决方案 > linkedList.find() 中的意外 gc 分配行为

问题描述

众所周知,如果我们将值类型变量与null进行比较,会导致GC alloc导致装箱:

{
    public class TestGeneric<T>{

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

但是,我发现 LinkedList(System.Collections.Generic) 的 Find(T value) 方法使用了相同的代码,例如

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

但是调用喜欢

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

不会导致任何 GC 分配。

我真的很困惑。任何机构有一个想法?请帮助。非常感谢。

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

测试环境:Unity 2018,Unity Profiler(Deep Profile Enable) .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);
        }
    }
}

unity profiler 显示

TestGC 方法导致每帧 200Byte GC Alloc。

list.Find 方法导致每帧 0Byte GC Alloc。

标签: c#unity3dc#-4.0

解决方案


似乎LinkedList<T>.Findhttps://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。


推荐阅读