dotnet C# 调用委托的 GetInvocationList 的对象分配
本文也叫跟着 Stephen Toub 大佬学性能优化系列,这是我从 Stephen Toub 大佬给 WPF 框架做性能优化学到的知识,在热路径下,也就是频繁调用的模块,如果调用了委托的 GetInvocationList 方法,那么将视委托的大小,每次创建不同大小的新数组对象,而在频繁调用的模块,将会创建大量的对象
如以下代码的一个委托,当然对于事件来说也是如此
Action action = Foo;
for (int i = 0; i < 10; i++)
{
action += Foo;
}
static void Foo()
{
}
如果调用了 action 的 GetInvocationList 方法,那么在每次调用都会申请一些内存,如使用以下代码进行测试
for (int i = 0; i < 100; i++)
{
var beforeAllocatedBytesForCurrentThread = GC.GetAllocatedBytesForCurrentThread();
var invocationList = action.GetInvocationList();
var afterAllocatedBytesForCurrentThread = GC.GetAllocatedBytesForCurrentThread();
Console.WriteLine(afterAllocatedBytesForCurrentThread - beforeAllocatedBytesForCurrentThread);
}
上面代码的 GetAllocatedBytesForCurrentThread 是一个放在 GC 层面的方法,可以用来获取当前线程分配过的内存大小,这是一个用来辅助调试的方法。详细请看 dotnet 使用 GC.GetAllocatedBytesForCurrentThread 获取当前线程分配过的内存大小
可以看到运行时的控制台输出如下
312
112
112
112
112
112
112
112
112
112
112
112
// 不水了
这是因为在底层的实现,调用 GetInvocationList 方法的代码如下
public override sealed Delegate[] GetInvocationList()
{
Delegate[] delegateArray;
if (!(this._invocationList is object[] invocationList))
{
delegateArray = new Delegate[1]{ (Delegate) this };
}
else
{
delegateArray = new Delegate[(int) this._invocationCount];
for (int index = 0; index < delegateArray.Length; ++index)
delegateArray[index] = (Delegate) invocationList[index];
}
return delegateArray;
}
可以看到每次都需要重新申请数组,然后给定数组里面的元素。如果在调用频繁的模块里面,不断调用 GetInvocationList 方法,将会有一定的性能损耗。如在 WPF 的移动鼠标等逻辑里面
一个优化的方法是,如果指定的委托或事件的加等次数比调用 GetInvocationList 的次数少,如 WPF 的 PreNotifyInput 等事件,此时可以通过在加等的时候缓存起来,这样后续的调用就不需要重新分配内存
以上优化的细节请看 Avoid calling GetInvocationList on hot paths by stephentoub · Pull Request #4736 · dotnet/wpf
可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 6ed312e74e286d581e3d609ed555447474259ae4
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
获取代码之后,进入 FairhojafallJeeleefuyi 文件夹
dotnet C# 调用委托的 GetInvocationList 的对象分配的更多相关文章
- C#如何反射出委托的签名,如何使用反射调用委托
本文阐述C#中如何反射出委托的签名,假如我们有委托FooDelegate定义如下 delegate double FooDelegate (string param, bool condition); ...
- WPF异常“调用线程无法访问此对象,因为另一个线程拥有该对象 ”
WPF中在对界面进行操作的时候,可能会遇到"调用线程无法访问此对象,因为另一个线程拥有该对象"异常,这是因为WPF中只有UI线程才能操作UI元素,非UI线程要访问UI时就会报异常了 ...
- 委托、Lambda表达式、事件系列04,委托链是怎样形成的, 多播委托, 调用委托链方法,委托链异常处理
委托是多播委托,我们可以通过"+="把多个方法赋给委托变量,这样就形成了一个委托链.本篇的话题包括:委托链是怎样形成的,如何调用委托链方法,以及委托链异常处理. □ 调用返回类型为 ...
- WPF 封装 dotnet remoting 调用其他进程
原文:WPF 封装 dotnet remoting 调用其他进程 本文告诉大家一个封装好的库,使用这个库可以快速搭建多进程相互使用. 目录 创建端口 调用软件 运行的类 运行C++程序 通道 使用 在 ...
- WPF [调用线程无法访问此对象,因为另一个线程拥有该对象。] 解决方案以及如何实现字体颜色的渐变
本文说明WPF [调用线程无法访问此对象,因为另一个线程拥有该对象.] 解决方案以及如何实现字体颜色的渐变 先来看看C#中Timer的简单说明,你想必猜到实现需要用到Timer的相关知识了吧. C# ...
- C# 调用Webservice并传递序列化对象
原文:C# 调用Webservice并传递序列化对象 C#动态调用WebService注意要点 1.动态调用的url后面注意一定要加上?WSDL 例如:string _url = "ht ...
- __new__方法首先调用并返回一个实例化对象
>>> class CapStr(str): def __new__(cls,string): string = string.upper() return str.__new__( ...
- python与java的内存机制不一样;java的方法会进入方法区直到对象消失 方法才会消失;python的方法是对象每次调用都会创建新的对象 内存地址都不i一样
python与java的内存机制不一样;java的方法会进入方法区直到对象消失 方法才会消失;python的方法是对象每次调用都会创建新的对象 内存地址都不i一样
- spring jdbctemplate调用存储过程,返回list对象
注:本文来源于< spring jdbctemplate调用存储过程,返回list对象 > spring jdbctemplate调用存储过程,返回list对象 方法: /** * 调用 ...
- 170630、springboot编程之普通类中调用spring管理的bean对象
我们知道如果我们要在一个类使用spring提供的bean对象,我们需要把这个类注入到spring容器中,交给spring容器进行管理,但是在实际当中,我们往往会碰到在一个普通的Java类中,想直接使用 ...
随机推荐
- k8s-master 设置调度污点
k8s master 调度污点 NoSchedule:K8Snode添加这个effecf类型污点,新的不能容忍的pod不能再调度过来,但是老的运行在node上不受影响 NoExecute:K8Snod ...
- css实现多余文字隐藏,用省略号代替
.txt{ overflow: hidden; //溢出内容隐藏 white-space: nowrap; //强制文本在一行内显示 text-overflow: ellipsis; //当对象内文本 ...
- AXI-自定义IP-PS设计
基于AXI4的自定义IP核的设计 1.实验目标 利用vivado中内置的AXI总线初始化的IP核设计工具,将自己设计的流水灯的PL代码打包成IP核外设,挂在PS上,通过PS上的按钮控制流水灯的开始和结 ...
- IDEA怎么添加类注释和方法注释模板
IDEA设置自动生成模板类和方法注释 一.模板类注释 在右侧粘贴如下代码: /** *@BelongsProject: ${PROJECT_NAME} *@BelongsPackage: ${PACK ...
- Android组件(菜鸟教程)
- echarts 中国地图tooltip实现提示框
point: 鼠标位置,如 [20, 40]. params: 同 formatter 的参数相同. dom: tooltip 的 dom 对象. rect: 只有鼠标在图形上时有效,是一个用x, y ...
- 7 HTML锚点应用
7 锚点应用 锚点( anchor )是超链接的一种应用,也叫命名锚记,锚点可以像一个定位器一样,可以实现页面内的链接跳转,运用相当普遍.例如,我们有一个网页,由于内容太多,导致页面很长,而且里面的内 ...
- 财务人提高竞争力必备的技能,怎么能少了ta!
从近年来大数据技术的发展趋势和相关产业飞速发展的状态,可以看出当前"数据分析"的热度可以说是有增无减,而且从市场上对数据分析人才的需求缺口也可以看出企业对数据分析的重视程度.未来随 ...
- DevEco Studio 3.1差异化构建打包,提升多版本应用开发效率
原文:https://mp.weixin.qq.com/s/8XtgZ-k0mGXCjKHfSXFoOg,点击链接查看更多技术内容. HUAWEI DevEco Studio是开发Harmo ...
- c# aspose操作word文档
背景 这个是一个操作word文档的插件 1.1插入图片 using Aspose.Words; using Aspose.Words.Drawing; using Aspose.Words.Rende ...