是否使用委托创建垃圾(Does using a delegate create garbage)

2019-08-19 17:04发布

我工作的XBOX360游戏,使用XNA。 在Xbox垃圾收集执行相当差相比于PC上的一个,因此保持所产生降到最低垃圾为顺利地进行游戏至关重要。

我记得读一次,调用一个委托创建垃圾,但现在我的生活找不到代表产生垃圾的任何引用。 难道我只是做这件事或者代表凌乱?

如果代表是暗示一种变通方法凌乱,奖励积分。

public delegate T GetValue<T>(T value, T[] args);

public static T Transaction<T>(GetValue<T> calculate, ref T value, params T[] args) where T : class
{
    T newValue = calculate(value, args);
    return foo(newValue);
}

我的代码看起来依稀像此刻,我能想到的唯一的解决办法,以摆脱自己代表的是在继承的接口IValueCalculator一个类来传递,然后我可以调用接口的方法,这是不是真的很整齐虽然!

Answer 1:

委托本身就是一个对象,因此,如果您创建一个委托,也许是一个匿名方法,并给这对一些其他方法来执行,并没有存储代表以供将来参考,那么, 将产生垃圾。

举例来说,这样的:

collection.ForEach(delegate(T item)
{
    // do something with item
});

在这种情况下,创建一个新的委托对象,但超出了调用ForEach它不被引用,因而有资格进行垃圾回收。

然而, 呼吁与会代表通过本身不产生垃圾,任何更比调用将相同类型的任何其它方法。 例如,如果你调用一个委托,它接受一个Object参数,传递一个Int32值,该值将被装箱,但如果你叫一个正常的方法相同的方式,以及会发生。

因此,使用的代表应该是好的,但过度的创建委托对象将是一个问题。


编辑 :对内存管理的Xbox和XNA一篇好文章是在这里: 托管在Xbox 360上的XNA代码性能:第2部分- GC和工具 。 注意这句话:

那么,如何一个控制GC延迟? 像NETCF的设备,在Xbox GC是不代。 这意味着,每一个集合是在托管堆中一个完整的集合。 因此,我们发现,GC延迟近似为线性到活动对象的数量...然后加入堆压缩成本上说。 我们的基准测试显示,深对象层次与浅的人之间的差别可以忽略不计,所以它主要是说事的对象的数量。 小物件也往往是一个便宜一点应对比大物体。

正如你所看到的,尽量避免创建大量不必要的对象,你应该有良好表现。



Answer 2:

在桌面环境的垃圾是有效的自由 。 在那里,你要担心的是有多少非垃圾你正在生产。 记住垃圾收集器是如何工作的:它首先标记所有已知的对象,然后将它清除所有活动对象标记并压缩存活的对象。 昂贵的步骤有“请取消活动对象”。 销毁垃圾便宜; 它的识别活对象是昂贵的,而且成本取决于你的活动对象(和它们的参考拓扑结构的复杂性)的数量,而不是对你有死的对象的数量。

然而,在XBOX和其他紧凑型框架,垃圾收集器相当频繁运行,并且运行更经常地创建新的分配时,所以是的,你是正确的担心也产生垃圾。 您既想保持住一套小(以使收集便宜),而不是进行新的分配(因为触发集合。)

创建一个委托不分配内存,但调用一个无非是调用一个名为类Invoke方法更多。 委托是不是比一个名为Invoke方法恰好立即调用另一个方法时,它被称为类等等。

无论如何,如果你有问题的内存性能再到做正确的事情是走出内存分析器,并用它来分析你的程序。 随机铸造约想知道如果这样或那样的情况来分配内存,就像试图剔除与指甲剪你的花园; 它需要大量的时间,实际上并没有实现自己的目标。 使用分析器来分析你的表现,看看问题所在,然后解决这些问题。



Answer 3:

代表创建产生的垃圾,因为别人已经指出。

在你的榜样,使用params参数可能产生的垃圾,以及。

考虑不使用params关键字提供过载。

这就是为什么有不同数量的参数重载通常使用的一个沿库方法存在的理由params关键字:

见的String.Format方法(String,对象[])

Format Method (String, Object)
Format Method (String, Object[])
...
Format Method (String, Object, Object)
Format Method (String, Object, Object, Object)


Answer 4:

是的,没有。

调用简单的委托对堆没有分配任何东西,但创建委托分配在堆64个字节。

为了避免GC,您可以预先创建的委托。

让我们来验证:

using BenchmarkDotNet.Running;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            var summary = BenchmarkRunner.Run<BenchmarkDelegate>();            
        }
    }
}

基准测试:

using BenchmarkDotNet.Attributes;

namespace Test
{
    [MemoryDiagnoser]
    public class BenchmarkDelegate
    {
        public delegate int GetInteger();

        GetInteger _delegateInstance;

        public BenchmarkDelegate()
        {
            _delegateInstance = WithoutDelegate;
        }

        [Benchmark]
        public int WithInstance() => RunDelegated(_delegateInstance);

        [Benchmark]
        public int WithDelegate() => RunDelegated(WithoutDelegate);

        public int RunDelegated(GetInteger del) => del();

        [Benchmark]
        public int WithoutDelegate() => 0;
    }
}

以下的输出,向右滚动看到分配的内存/运算柱:

DefaultJob : .NET Core 2.2.1 (CoreCLR 4.6.27207.03, CoreFX 4.6.27207.03), 64bit RyuJIT
|          Method |       Mean |     Error |    StdDev | Gen 0/1k Op | Gen 1/1k Op | Gen 2/1k Op | Allocated Memory/Op |
|---------------- |-----------:|----------:|----------:|------------:|------------:|------------:|--------------------:|
|    WithInstance |  7.5503 ns | 0.0751 ns | 0.0702 ns |           - |           - |           - |                   - |
|    WithDelegate | 35.4866 ns | 1.0094 ns | 1.2766 ns |      0.0203 |           - |           - |                64 B |
| WithoutDelegate |  0.0000 ns | 0.0000 ns | 0.0000 ns |           - |           - |

       - |                   - |


文章来源: Does using a delegate create garbage