为何C#中List.Sort((x,y)=>x-y)无内存分配?
为什么List.Sort(Comparison)看似创建新对象却无内存分配?
以下是
List<T>.Sort(Comparison<T>)的核心实现代码:
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); } }
从代码看,每次调用Sort时都会创建一个Array.FunctorComparer<T>对象,但运行下面的测试代码后,却发现没有内存分配:
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); } }
核心原因解析
Array.FunctorComparer<T>是值类型
你看到的new关键字容易产生误导——实际上Array.FunctorComparer<T>是一个struct(值类型),而非引用类型。值类型的实例分配在栈上,不会占用托管堆内存,自然不会被GC.GetTotalMemory统计到。JIT编译器的内联优化
JIT会对这段代码执行激进优化:它会直接将FunctorComparer的比较逻辑内联到Sort方法中,甚至完全消除这个临时结构体的创建,直接使用传入的Comparison<T>委托完成比较操作,彻底避免了额外的内存开销。无捕获lambda的委托缓存
测试代码中的(x,y) => x - y没有捕获外部变量,JIT会将它编译为静态方法,并缓存对应的委托实例。因此多次调用Sort时,不会每次都创建新的委托对象,进一步减少了潜在的内存分配。
内容的提问来源于stack exchange,提问作者M SLICENT
相关产品推荐
相关产品推荐

