.net BinaryFormatter序列化對象慢的原因


    最近在做組件對象寫入流的優化,因此對一些.net下序列化組件做了一些測試,分別針對ProtoBuf.net 和.net自帶的BinaryFormatter進行了分析.從測試的結果來看BinaryFormatter的性能和ProtoBuf.net的性能足足相差了10倍。為什么差這么遠呢,如果緊緊從運行時間來看可能以為BinaryFormatter一定是使用反射什么的,所以導致結果這么慢。為了更清楚的了解具體情況於是對兩者的測試代碼進行了一個內存分析.

ProtoBuf.net的測試代碼

        public void PB(int count)
        {
            TestPB obj = new TestPB();
            obj.Email = "henryfan@test.com";
            obj.FirstName = "henry";
            obj.LastName = "fan";
            obj.ID = 3456;
            obj.Phone = "13418888121";
            obj.Type = 67;
            System.IO.MemoryStream stream = new System.IO.MemoryStream(265);
            stream.Position = 0;
            ProtoBuf.Serializer.Serialize<TestPB>(stream, obj);
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Reset();
            sw.Start();
            for (int i = 0; i < count; i++)
            {
                stream.Position = 0;
                ProtoBuf.Serializer.Serialize<TestPB>(stream, obj);
            }
            sw.Stop();
            Console.WriteLine("ProtoBuf Serialize Objects{0} Time:{1}", count, sw.Elapsed.TotalMilliseconds);
        }

BinaryFormatter的測試代碼

        public void DotNet(int count)
        {

            TestDotNet obj = new TestDotNet();
            obj.Email = "henryfan@test.com";
            obj.FirstName = "henry";
            obj.LastName = "fan";
            obj.ID = 3456;
            obj.Phone = "13418888121";
            obj.Type = 67;
            System.IO.MemoryStream stream = new System.IO.MemoryStream(256);
            BinaryFormatter bf = new BinaryFormatter();
            stream.Position = 0;
            bf.Serialize(stream, obj);
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Reset();
            sw.Start();
            for (int i = 0; i < count; i++)
            {
                stream.Position = 0;
                bf.Serialize(stream, obj);
            }
            sw.Stop();
            Console.WriteLine("BinaryFormatter Serialize Objects{0} Time:{1}", count,sw.Elapsed.TotalMilliseconds);
        }

通過內存分析針對上面代碼進行100000次的序列化對象查看其內存開銷的情況

ProtoBuf.net 的內存使用情況

名稱 非獨占分配數 獨占分配數 非獨占字節數 獨占字節數 非獨占分配數百分比
+ ProtoBuf.ProtoWriter 100,001 100,001 6,000,060 6,000,060 24.44
+ ProtoBuf.NetObjectCache 100,001 100,001 2,400,024 2,400,024 24.44
+ ProtoBuf.Meta.RuntimeTypeModel.TypeFinder 200,002 200,002 2,400,024 2,400,024 48.88
+ System.Byte[] 1,199 1,199 2,111,060 2,111,060 0.29
+ System.String 697 697 32,418 32,418 0.17
+ System.Char[] 44 44 25,382 25,382 0.01
+ System.Object[] 350 350 20,300 20,300 0.09
+ System.Collections.Generic.List`1 589 589 14,136 14,136 0.14
+ System.Reflection.Emit.OpCode 226 226 9,944 9,944 0.06
+ System.Reflection.MethodInfo[] 256 256 9,012 9,012 0.06
+ System.Reflection.RuntimeMethodInfo 123 123 6,888 6,888 0.03
+ System.Collections.ArrayList 259 259 6,216 6,216 0.06

BinaryFormatter的內存使用情況

名稱 非獨占分配數 獨占分配數 非獨占字節數 獨占字節數 非獨占分配數百分比
+ System.Collections.Hashtable.bucket[] 500,008 500,008 72,001,656 72,001,656 8.77
+ System.Object[] 600,012 600,012 39,204,636 39,204,636 10.52
+ System.Byte[] 201,074 201,074 31,699,205 31,699,205 3.53
+ System.Collections.Hashtable 500,008 500,008 28,000,448 28,000,448 8.77
+ System.Runtime.Serialization.Formatters.Binary.NameInfo 400,004 400,004 19,200,192 19,200,192 7.01
+ System.String 100,078 100,078 19,005,036 19,005,036 1.75
+ System.Int64[] 100,001 100,001 17,200,172 17,200,172 1.75
+ System.Runtime.Serialization.Formatters.Binary.ObjectWriter 100,001 100,001 10,400,104 10,400,104 1.75
+ System.Runtime.Serialization.Formatters.Binary.__BinaryWriter 100,001 100,001 10,000,100 10,000,100 1.75
+ System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo 100,001 100,001 6,800,068 6,800,068 1.75
+ System.Runtime.Serialization.Formatters.Binary.SerStack 200,002 200,002 4,800,048 4,800,048 3.51
+ System.Runtime.Serialization.Formatters.Binary.BinaryObjectWithMapTyped 100,001 100,001 4,400,044 4,400,044 1.75

從上面兩個內存分析結果來看就一目了然了,ProtoBuf.net在序列化的過程中緊緊只開銷了13MB左右的內存,所創建對象的總數大概在400000個左右;反觀BinaryFormatter在序列化過程確使用了300多MB的內存,創建對象總數接近6000000個。緊緊是對象的創建對象的數量就已經是ProtoBuf.net 10倍,因此效率慢就是正常的事。MS為什么這樣做這個就不得而知了,明明可以做得很好的,但確並沒這樣做……


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM