为什么在C#中使用`list.Sort((x, y) => x – y)`不会发生内存分配。

huangapple go评论70阅读模式
英文:

why list.Sort((x ,y) => x - y) has no memory allocation in C#

问题

以下是您提供的内容的翻译:

C#源代码:
text

public void Sort(Comparison<T> comparison) {
    if( comparison == null) {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
    }
    Contract.EndContractBlock();

    if( _size > 0) {
        IComparer<T> comparer = new Array.FunctorComparer<T>(comparison);
        Array.Sort(_items, 0, _size, comparer);
    }
}

这行代码:
IComparer comparer = new Array.FunctorComparer(comparison);
显示每次对数组进行排序时,都会创建一个新对象。但当我多次运行它时,我发现根本没有分配。为什么?

这是我的测试代码:

public static void Main(string[] args)
{
    List<int> list = new List<int>();
    list.Add(1);
    list.Add(2);
    for (int i = 0; i < 10; ++i)
    {
        long cnt = GC.GetTotalMemory(false);
        list.Sort((x, y) => x - y);
        Console.WriteLine(GC.GetTotalMemory(false) - cnt);
    }
}
英文:

the C# source code:
text

public void Sort(Comparison&lt;T&gt; comparison) {
    if( comparison == null) {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
    }
    Contract.EndContractBlock();

    if( _size &gt; 0) {
        IComparer&lt;T&gt; comparer = new Array.FunctorComparer&lt;T&gt;(comparison);
        Array.Sort(_items, 0, _size, comparer);
    }
}

this line
IComparer&lt;T&gt; comparer = new Array.FunctorComparer&lt;T&gt;(comparison);
shows that every time you sort an array, it will create a new object. But when I ran it many times, I found it has no allocation at all.Why?

Here is my test code.

public static void Main(string[] args)
{
    List&lt;int&gt; list = new List&lt;int&gt;();
    list.Add(1);
    list.Add(2);
    for (int i = 0; i &lt; 10; ++i)
    {
        long cnt = GC.GetTotalMemory(false);
        list.Sort((x ,y) =&gt; x - y);
        Console.WriteLine(GC.GetTotalMemory(false) - cnt);
    }
}

答案1

得分: 5

现在不清楚您是否在使用.NET 6/7或.NET Framework 4.x。然而,如果您使用的是.NET Framework 4.x,List&lt;T&gt;.Sort 方法会分配内存。

与直接使用 GC 方法相比,最好使用一个专门设计用于此类操作的基准测试库。我推荐使用 BenchmarkDotNet。例如,像这样的小程序:

using System.Collections.Generic;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;

public static class Program
{
    public static void Main()
    {
        BenchmarkRunner.Run&lt;Benchmarks&gt;();
    }
}

[MemoryDiagnoser] // 输出内存分配
[SimpleJob(RuntimeMoniker.Net70)]
[SimpleJob(RuntimeMoniker.Net481)]
public class Benchmarks
{
    private readonly List&lt;int&gt; _list = new List&lt;int&gt;() { 1, 2 };

    [Benchmark]
    public void SortList()
    {
        _list.Sort((x, y) =&gt; x - y);
    }
}

将给您输出类似于以下的结果:

Method Job Runtime Mean Error StdDev Gen0 Allocated
SortList .NET 7.0 .NET 7.0 7.989 ns 0.1608 ns 0.1343 ns - -
SortList .NET Framework 4.8.1 .NET Framework 4.8.1 28.208 ns 0.5812 ns 0.9385 ns 0.0038 24 B

现在您可以看到,它确实会根据使用的框架分配 0 字节或 24 字节。

英文:

It's not clear if you are using .NET 6/7 or .NET Framework 4.x. However, the List&lt;T&gt;.Sort method does allocate memory if you are using .NET Framework 4.x.

Instead of directly using the GC methods, it's far better to use a benchmarking library that is specifically designed to do things like this. I recommend BenchmarkDotNet. For example, a small program like this:

using System.Collections.Generic;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;

public static class Program
{
    public static void Main()
    {
        BenchmarkRunner.Run&lt;Benchmarks&gt;();
    }
}

[MemoryDiagnoser] // output memory allocations
[SimpleJob(RuntimeMoniker.Net70)]
[SimpleJob(RuntimeMoniker.Net481)]
public class Benchmarks
{
    private readonly List&lt;int&gt; _list = new List&lt;int&gt;() { 1, 2 };

    [Benchmark]
    public void SortList()
    {
        _list.Sort((x, y) =&gt; x - y);
    }
}

Will give you output something like this:

Method Job Runtime Mean Error StdDev Gen0 Allocated
SortList .NET 7.0 .NET 7.0 7.989 ns 0.1608 ns 0.1343 ns - -
SortList .NET Framework 4.8.1 .NET Framework 4.8.1 28.208 ns 0.5812 ns 0.9385 ns 0.0038 24 B

Now you can see that it does indeed allocate either 0 bytes or 24 bytes depending on which framework you are using.

huangapple
  • 本文由 发表于 2023年5月17日 19:32:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76271625.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定