linkedList.find()中出现意外的gc分配行为

3

众所周知,如果我们将一个值类型的变量与null进行比较,这将导致装箱引起的GC分配:

{
    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(启用深度分析),.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分析器显示:

TestGC方法每帧引起了200字节的GC分配。

list.Find方法每帧引起了0字节的GC分配。


这是实现的代码:https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,a8a85c5fb1a25488 - Milos Romanic
它使用 if(match(_items[i])) 来比较值,我不确定那是什么意思 :D - Milos Romanic
@Milos,看起来你指向了List的实现,而不是LinkedList... - Bruno Belmondo
哦,我的错。这是LinkedList的链接:https://referencesource.microsoft.com/#System/compmod/system/collections/generic/linkedlist.cs,74e4e6394382badc,references - Milos Romanic
1个回答

0

看起来 LinkedList<T>.Find (https://referencesource.microsoft.com/#System/compmod/system/collections/generic/linkedlist.cs,74e4e6394382badc,references)

使用 EqualityComparer<T> 来比较值,而这个类又使用 IEquatable<T>.Equals(T) (https://learn.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。


2
首先,它仍然使用 if (value != null),而且Unity不使用这个版本的 LinkeList,因为它使用Mono库,但是该条件仍然在那里使用。 - Dmytro Mukalov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接