其实很多写.NET程序的开发人员都很喜欢通过一些计时器来看来一程序或代码的运行效率,的确这样是可以计算出代码执行所损耗的时间。但.net程序的优化不仅仅在于此.大家知道.net提供自动内存回收机制,让我们不用烦恼内存回收问题;同样.net提供给我们的内存分配机制也很出色,因为它能非常快速地帮我们进行内存分配工作。当我们在享受吃糖的乐趣的时候,别忘了这东西吃多了很容易把牙齿给搞坏的;同样.net 回收内存的时候同样也让难受,当然这些情况不会在你资源充足的时候给你带来烦恼;不过一但出现他足可以让你吃不下饭。
所以优化.net程序的时候不要忘了GC这东西,解决他的办法只有一个就是分析那里产生内存,想尽办法去产生内存的地方给干了(说得有点粗爆).前段时间了解了一个对象序列化组件,测试了一下性能发现其效率真的很出色。测试代码如下:
int count = 100000; KJFObject kobj = new KJFObject(); kobj.Mm = new int[] { 34, 24, 545 }; kobj.Haha = "asfsfasfasfas"; kobj.Bind(); System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); for (int i = 0; i < count; i++) { kobj = new KJFObject(); kobj.Mm = new int[] { 34, 24, 545 }; kobj.Haha = "asfsafsafsafasdfasfasf"; kobj.Bind(); } sw.Stop(); Console.WriteLine(sw.Elapsed.TotalMilliseconds); BufferWriter writer = new BufferWriter(Encoding.UTF8); sw.Reset(); sw.Start(); for (int i = 0; i < count; i++) { BObject bobj = new BObject(); bobj.Mm = new int[] { 34, 24, 545 }; bobj.Haha = "asfsafsafsafasdfasfasf"; writer.Reset(); bobj.Save(writer); } Console.WriteLine(sw.Elapsed.TotalMilliseconds);
他的序列化效率比直接代码方式效率只低了50%,这50%的差距带的效果就是编写对象的时候更灵光和代码更少,这是完全可取的。其实测试结果是偏向于后者,如果细心的朋友一定发现一个问题,BufferWriter是可复用的;如果没有这种机制的情况那后者是完全输给前者的。以下是两个实体的定义
public class KJFObject: IntellectObject { private int[] _mm; [IntellectProperty(0)] public int[] Mm { get { return _mm; } set { _mm = value; } } private string _haha; [IntellectProperty(1)] public string Haha { get { return _haha; } set { _haha = value; } } } public class BObject:IMessage { private int[] _mm; public int[] Mm { get { return _mm; } set { _mm = value; } } private string _haha; public string Haha { get { return _haha; } set { _haha = value; } } public void Load(BufferReader reader) { Mm = reader.ReadInt32s(); Haha = reader.ReadString(); } public void Save(BufferWriter writer) { writer.Write(Mm); writer.Write(Haha); } }
如果紧紧是这样效率上的差异,那必然不会选择手写代码来做,因为手写代码不好维护,容易出错特别是在大量成员读写顺序上.从效率上来说这个组件可以说是完全胜任。当我在做一下步测试的时候发现组件的问题,就是没有内存复用机制;于是用内存分析工具分析一下内存使用状况。发现其内存使用情况有点差,内存的开销有点大,在大并发下其GC压力估计不少。以下是一个测结果:
从测试结果来看排在前头的有Enumerator,这东西是怎产生的呢,其实就是我们习惯用Foreach产生的,从执行效率上来说Foreach和for没多大差异,差别就在内存分配和回收上。当然你能通过用for把这个对象的开销干了,能就更好的事情.byte[] char[]这些都可以通过复用的给干了,这样大头内存开销基本就没有了。
那手写代码控制序列化同样的工作其内存使用又怎样呢
从内存使用结果来看其差距还是非常大的,足足有5-6倍的差异,这些内存的GC回来在高并发下足可以让整体处理性能最少有着10%的提升。所以内存复用在.net程序优化中起着十分重要的作用,只是这种优化能体现出来的场景有限;不过当你的产品面对运营的时候发现那就是件比较麻烦的事情,因为这些调整很有可能影响一些核心的地方。当你面对高性能应用的时候别忘了GC这个家伙,它真是一个要命的东西。