【Winform】ListView虚拟模式与普通模式的性能对比 -- 深入分析
2014-01-17 08:35
453 查看
本文对我的上一篇文章ListView虚拟模式与普通模式的性能对比进行了更深入的分析。上一篇文章可视为如何使用虚拟模式,这篇文章分析了虚拟模式的原理。
1、 从代码上分析:
普通模式使用的是Collection.Add()这种方法来添加数据。
虚拟模式使用的是在事件RetrieveVirtualItem中使用e.Item = Collection[e.ItemIndex];这种方法来添加数据。
貌似看不出什么端倪,那么我们请出IL DSAM反编译生成的exe文件来从IL上分析。
2、 从IL分析:(IL代码部分省略,只显示关键部分。)
普通模式Collection.Add()和虚拟模式e.Item = Collection[e.ItemIndex]
普通模式IL代码如图:
[System.Windows.Forms]System.Windows.Forms.ListViewItem[])为普通模式添加数据的代码
虚拟模式IL代码如图:
接下来需要请出ILSpy或者Reflector来帮我们分析这两句关键代码的内在不同。(省略了众多步分析过程)
虚拟模式IL_0030:System.Windows.Forms.RetrieveVirtualItemEventArgs::set_Item
相当于只创建了一个class A(class A与class B的结构完全相同), 然后不停的把新的class B赋给class A,以覆盖class A中原有的数据,就有点像 int x = 0; x += 1; 只创建了一个x对象,然后不停的覆盖原有的x值。至于index是由RetrieveVirtualItemEventArgs类内部做的处理,详情见代码:
普通模式IL_00d8:System.Windows.Forms.ListView/ListViewItemCollection::AddRange(class
[System.Windows.Forms]System.Windows.Forms.ListViewItem[])
请注意括号中的红色部分,这部分是new 出来了N个ListViewItem类,并使用其默认的构造函数。
总结
至于为什么微软这么做不得而知,但是这点给我了个启示,如果两个class/struct/array结构完全相同,那么是否可以通过另外处理index的方法来把不同的N个class/struct/array使用数据覆盖的方式来进行赋值,只需要new出一个新对象,而不是产生N个全新的对象再进行处理,这样程序的运行效率会大幅度的提升。
1、 从代码上分析:
普通模式使用的是Collection.Add()这种方法来添加数据。
虚拟模式使用的是在事件RetrieveVirtualItem中使用e.Item = Collection[e.ItemIndex];这种方法来添加数据。
貌似看不出什么端倪,那么我们请出IL DSAM反编译生成的exe文件来从IL上分析。
2、 从IL分析:(IL代码部分省略,只显示关键部分。)
普通模式Collection.Add()和虚拟模式e.Item = Collection[e.ItemIndex]
普通模式IL代码如图:
.method private hidebysig instance void Btn_GenerateClick(object sender, class [mscorlib]System.EventArgs e) cil managed { // Code size 222 (0xde) .maxstack 5 .locals init (int32 V_0, int32 V_1, int32 V_2, int32 V_3, int32 V_4, int32 V_5) IL_0000: ldarg.0 IL_0001: ldnull IL_0002: stfld class [System.Windows.Forms]System.Windows.Forms.ListViewItem[] ListViewVirtualMode.ListViewWithoutVirtualMode::_itemsCacheCollection IL_0007: ldarg.0 IL_0008: ldfld class [System.Windows.Forms]System.Windows.Forms.ListView ListViewVirtualMode.ListViewWithoutVirtualMode::listView1 IL_000d: callvirt instance void [System.Windows.Forms]System.Windows.Forms.ListView::Clear() IL_0012: ldarg.0 IL_0013: ldfld class [System.Windows.Forms]System.Windows.Forms.TextBox ListViewVirtualMode.ListViewWithoutVirtualMode::textBox_RowTotal IL_0018: callvirt instance string [System.Windows.Forms]System.Windows.Forms.Control::get_Text() IL_001d: call int32 [mscorlib]System.Convert::ToInt32(string) IL_0022: stloc.0 IL_0023: ldarg.0 IL_0024: ldloc.0 IL_0025: newarr [System.Windows.Forms]System.Windows.Forms.ListViewItem IL_002a: stfld class [System.Windows.Forms]System.Windows.Forms.ListViewItem[] ListViewVirtualMode.ListViewWithoutVirtualMode::_itemsCacheCollection IL_002f: ldarg.0 IL_0030: ldfld class [System.Windows.Forms]System.Windows.Forms.CheckBox ListViewVirtualMode.ListViewWithoutVirtualMode::checkBox_PictureCol IL_0035: callvirt instance bool [System.Windows.Forms]System.Windows.Forms.CheckBox::get_Checked() IL_003a: brtrue.s IL_006c IL_003c: ldc.i4.0 IL_003d: stloc.1 IL_003e: br.s IL_0066 IL_0040: ldarg.0 IL_0041: ldfld class [System.Windows.Forms]System.Windows.Forms.ListViewItem[] ListViewVirtualMode.ListViewWithoutVirtualMode::_itemsCacheCollection IL_0046: ldloc.1 IL_0047: ldstr "item" IL_004c: ldloc.1 IL_004d: ldc.i4.1 IL_004e: add IL_004f: stloc.3 IL_0050: ldloca.s V_3 IL_0052: call instance string [mscorlib]System.Int32::ToString() IL_0057: call string [mscorlib]System.String::Concat(string, string) IL_005c: newobj instance void [System.Windows.Forms]System.Windows.Forms.ListViewItem::.ctor(string) IL_0061: stelem.ref IL_0062: ldloc.1 IL_0063: ldc.i4.1 IL_0064: add IL_0065: stloc.1 IL_0066: ldloc.1 IL_0067: ldloc.0 IL_0068: blt.s IL_0040 IL_006a: br.s IL_00c7 IL_006c: ldc.i4.0 IL_006d: stloc.2 IL_006e: br.s IL_00c3 IL_0070: ldloc.2 IL_0071: ldc.i4.2 IL_0072: rem IL_0073: brtrue.s IL_009b IL_0075: ldarg.0 IL_0076: ldfld class [System.Windows.Forms]System.Windows.Forms.ListViewItem[] ListViewVirtualMode.ListViewWithoutVirtualMode::_itemsCacheCollection IL_007b: ldloc.2 IL_007c: ldstr "item" IL_0081: ldloc.2 IL_0082: ldc.i4.1 IL_0083: add IL_0084: stloc.s V_4 IL_0086: ldloca.s V_4 IL_0088: call instance string [mscorlib]System.Int32::ToString() IL_008d: call string [mscorlib]System.String::Concat(string, string) IL_0092: ldc.i4.0 IL_0093: newobj instance void [System.Windows.Forms]System.Windows.Forms.ListViewItem::.ctor(string, int32) IL_0098: stelem.ref IL_0099: br.s IL_00bf IL_009b: ldarg.0 IL_009c: ldfld class [System.Windows.Forms]System.Windows.Forms.ListViewItem[] ListViewVirtualMode.ListViewWithoutVirtualMode::_itemsCacheCollection IL_00a1: ldloc.2 IL_00a2: ldstr "item" IL_00a7: ldloc.2 IL_00a8: ldc.i4.1 IL_00a9: add IL_00aa: stloc.s V_5 IL_00ac: ldloca.s V_5 IL_00ae: call instance string [mscorlib]System.Int32::ToString() IL_00b3: call string [mscorlib]System.String::Concat(string, string) IL_00b8: ldc.i4.1 IL_00b9: newobj instance void [System.Windows.Forms]System.Windows.Forms.ListViewItem::.ctor(string, int32) IL_00be: stelem.ref IL_00bf: ldloc.2 IL_00c0: ldc.i4.1 IL_00c1: add IL_00c2: stloc.2 IL_00c3: ldloc.2 IL_00c4: ldloc.0 IL_00c5: blt.s IL_0070 IL_00c7: ldarg.0 IL_00c8: ldfld class [System.Windows.Forms]System.Windows.Forms.ListView ListViewVirtualMode.ListViewWithoutVirtualMode::listView1 IL_00cd: callvirt instance class [System.Windows.Forms]System.Windows.Forms.ListView/ListViewItemCollection [System.Windows.Forms]System.Windows.Forms.ListView::get_Items() IL_00d2: ldarg.0 IL_00d3: ldfld class [System.Windows.Forms]System.Windows.Forms.ListViewItem[] ListViewVirtualMode.ListViewWithoutVirtualMode::_itemsCacheCollection IL_00d8: callvirt instance void [System.Windows.Forms]System.Windows.Forms.ListView/ListViewItemCollection::AddRange(class [System.Windows.Forms]System.Windows.Forms.ListViewItem[]) IL_00dd: ret } // end of method ListViewWithoutVirtualMode::Btn_GenerateClick其中最后部分IL_00d8:System.Windows.Forms.ListView/ListViewItemCollection::AddRange(class
[System.Windows.Forms]System.Windows.Forms.ListViewItem[])为普通模式添加数据的代码
虚拟模式IL代码如图:
.method private hidebysig instance void listView1_RetrieveVirtualItem(object sender, class [System.Windows.Forms]System.Windows.Forms.RetrieveVirtualItemEventArgs e) cil managed { // Code size 54 (0x36) .maxstack 3 .locals init (int32 V_0) IL_0000: ldarg.0 IL_0001: ldfld class [System.Windows.Forms]System.Windows.Forms.ListViewItem[] ListViewVirtualMode.ListViewWithVirtualMode::_itemsCacheCollection IL_0006: brfalse.s IL_001c IL_0008: ldarg.2 IL_0009: ldarg.0 IL_000a: ldfld class [System.Windows.Forms]System.Windows.Forms.ListViewItem[] ListViewVirtualMode.ListViewWithVirtualMode::_itemsCacheCollection IL_000f: ldarg.2 IL_0010: callvirt instance int32 [System.Windows.Forms]System.Windows.Forms.RetrieveVirtualItemEventArgs::get_ItemIndex() IL_0015: ldelem.ref IL_0016: callvirt instance void [System.Windows.Forms]System.Windows.Forms.RetrieveVirtualItemEventArgs::set_Item(class [System.Windows.Forms]System.Windows.Forms.ListViewItem) IL_001b: ret IL_001c: ldarg.2 IL_001d: ldarg.2 IL_001e: callvirt instance int32 [System.Windows.Forms]System.Windows.Forms.RetrieveVirtualItemEventArgs::get_ItemIndex() IL_0023: stloc.0 IL_0024: ldloca.s V_0 IL_0026: call instance string [mscorlib]System.Int32::ToString() IL_002b: newobj instance void [System.Windows.Forms]System.Windows.Forms.ListViewItem::.ctor(string) IL_0030: callvirt instance void [System.Windows.Forms]System.Windows.Forms.RetrieveVirtualItemEventArgs::set_Item(class [System.Windows.Forms]System.Windows.Forms.ListViewItem) IL_0035: ret } // end of method ListViewWithVirtualMode::listView1_RetrieveVirtualItem其中IL_0030:System.Windows.Forms.RetrieveVirtualItemEventArgs::set_Item为虚拟模式添加数据的代码
接下来需要请出ILSpy或者Reflector来帮我们分析这两句关键代码的内在不同。(省略了众多步分析过程)
虚拟模式IL_0030:System.Windows.Forms.RetrieveVirtualItemEventArgs::set_Item
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] public void set_Item(ListViewItem value) { this.item = value; }
相当于只创建了一个class A(class A与class B的结构完全相同), 然后不停的把新的class B赋给class A,以覆盖class A中原有的数据,就有点像 int x = 0; x += 1; 只创建了一个x对象,然后不停的覆盖原有的x值。至于index是由RetrieveVirtualItemEventArgs类内部做的处理,详情见代码:
namespace System.Windows.Forms { using System; using System.Runtime; public class RetrieveVirtualItemEventArgs : EventArgs { private ListViewItem item; private int itemIndex; [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] public RetrieveVirtualItemEventArgs(int itemIndex) { this.itemIndex = itemIndex; } public ListViewItem Item { [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get { return this.item; } [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set { this.item = value; } } public int ItemIndex { [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get { return this.itemIndex; } } } }
普通模式IL_00d8:System.Windows.Forms.ListView/ListViewItemCollection::AddRange(class
[System.Windows.Forms]System.Windows.Forms.ListViewItem[])
请注意括号中的红色部分,这部分是new 出来了N个ListViewItem类,并使用其默认的构造函数。
public void AddRange(ListViewItem[] items) { if (items == null) { throw new ArgumentNullException("items"); } this.InnerList.AddRange(items); }
using System; using System.Collections; using System.Reflection; using System.Windows.Forms; internal interface IInnerList { ListViewItem Add(ListViewItem item); void AddRange(ListViewItem[] items); void Clear(); bool Contains(ListViewItem item); void CopyTo(Array dest, int index); IEnumerator GetEnumerator(); int IndexOf(ListViewItem item); ListViewItem Insert(int index, ListViewItem item); void Remove(ListViewItem item); void RemoveAt(int index); int Count { get; } ListViewItem this[int index] { get; set; } bool OwnerIsDesignMode { get; } bool OwnerIsVirtualListView { get; } }由于AddRange并未对Index作出特别处理,而使用的是ListViewItem自带的index,结果最终导致产生了N个对象。
总结
至于为什么微软这么做不得而知,但是这点给我了个启示,如果两个class/struct/array结构完全相同,那么是否可以通过另外处理index的方法来把不同的N个class/struct/array使用数据覆盖的方式来进行赋值,只需要new出一个新对象,而不是产生N个全新的对象再进行处理,这样程序的运行效率会大幅度的提升。
相关文章推荐
- 嵌入式arm linux环境中gdb+gdbserver调试
- linux 乱码解决篇
- 第五次浪潮
- 使用map关联容器实现单词转换的程序
- 寒假集训第三天——栈和队列
- 菜根谭#54
- SMARTCLIENT入门教程之一——前言
- Java 安全模型介绍
- 【经典例题】55555最大三位数约数
- 学习cocos2dx问题记录
- Java: 复制文件最快方法
- windows消息机制(MFC)
- Linux下开发关于Samba/Vimrc/svn/tftp/等基本的配置使用
- [LeetCode] Binary Tree Maximum Path Sum
- C++感悟
- Java里this的用法
- 接口测试之脚本用例
- LCS最长公共子序列C++代码实现
- VM虚拟机的配置文件(.vmx)损坏修复
- Go与C语言的互操作