我需要能够使用Mono在C#中基于函数指针调用单个方法。Delegate(委托)可用于此目的,但它们似乎每次设置委托时都会分配52字节的内存(不是 +=,只是使用 = 设置委托,因此委托引用的始终是一个方法)。
这个委托每秒钟会多次更改,这导致GC定期启动,我想避免这种情况。
我不介意最初的内存分配,但是否有一种方法可以防止每次更改单个委托值时都进行一次内存分配?
如果没有,除了Delegate之外,还有其他动态调用C#方法的方法吗,这些方法不会每次更改地址时都分配任何内存?
我需要能够使用Mono在C#中基于函数指针调用单个方法。Delegate(委托)可用于此目的,但它们似乎每次设置委托时都会分配52字节的内存(不是 +=,只是使用 = 设置委托,因此委托引用的始终是一个方法)。
这个委托每秒钟会多次更改,这导致GC定期启动,我想避免这种情况。
我不介意最初的内存分配,但是否有一种方法可以防止每次更改单个委托值时都进行一次内存分配?
如果没有,除了Delegate之外,还有其他动态调用C#方法的方法吗,这些方法不会每次更改地址时都分配任何内存?
Action action = foo.DoSomething;
Action action = new Action(foo.DoSomething);
这就是分配的来源。没有完美的解决方法,但为了防止分配,您需要缓存和重用委托。
您可以通过为每个方法创建一个委托来在实现方面实现此目标。
public class Foo
{
public void DoSomething() { /*nop*/ }
private Action _doSomethingDelegate;
public Action DoSomethingDelegate
{
get { return _doSomethingDelegate ?? (_doSomethingDelegate = DoSomething); }
}
}
Action action = foo.DoSomethingDelegate;
另一个选择是使用某种缓存类,但这会引入一堆对象生命周期问题,在游戏场景中可能不太合适。这是一种比较粗糙的实现,真正的实现可能需要使用弱引用。
public static class DelegateCache
{
private static readonly Dictionary<object, Dictionary<string, Delegate>> Cache = new Dictionary<object, Dictionary<string, Delegate>>();
private static Dictionary<string, Delegate> GetObjectCache(object instance)
{
Dictionary<string, Delegate> delegates;
if (!Cache.TryGetValue(instance, out delegates))
{
Cache[instance] = delegates = new Dictionary<string, Delegate>();
}
return delegates;
}
public static T GetDelegate<T>(object instance, string method)
where T: class
{
var delegates = GetObjectCache(instance);
Delegate del;
if (!delegates.TryGetValue(method, out del))
{
delegates[method] = del = Delegate.CreateDelegate(typeof(T), instance, method);
}
return del as T;
}
}
Action action = DelegateCache.GetDelegate<Action>(foo, "DoSomething");
经过测试,这两种方法每个对象/方法对仅有一个分配。尽管实现方案需要大量工作,但我可能会选择它,因为它更加简洁。如果有很多方法并且您计划添加许多方法,则可以使用T4生成带有委托实现的部分类。