通過分析內存來優化.NET程序


最近在做一個MSMQ的Agent服務,在這里分享一下這個服務在優化的一點經驗,通過分析內存更准確地定位出程序中存在的性能問題,從而讓程序的性能以倍數的提升.

問題的引發

由於通過.NET MSMQ的Client實現消息分布和故障轉移實在測試效果並不理想..所以決定實現一個MSMQ的Agent服務,由於有網絡編寫的經驗所以對實現的效果還有很有信心的.可惜最終實現出來的效果實在慘不忍睹...4個連接並發消息寫入只有150/秒,實在是完全坑爹的結果!在架構上的設計並不存在問題,所以問題一定存在程序實現過程中,以往的經驗告訴自己做內存分析是最直接的辦法.

問題排查一Buffer沒正常回收到Pool

由於在測試過程CPU使用率並不高,所以懷疑是Buffer沒有回收到Pool導致

從分析的結果來說,的確是自己在寫代碼的時候犯錯了...存在大量的buffer被Pop出來導致大量內存被創建.但從代碼流程上來看找不到任何原因.

public override void MessageWrite(IMessage msg, BufferWriter writer)
        {
            HttpData hb = msg as HttpData;  
            try
            {
                using (hb.Message)
                {
                    msg.Save(writer);
                }
            }
            finally
            {
                
                if (hb != null)
                {
                    hb.Message = null;
                    HttpDataPackage.HttpDataPool.Push(hb);
                }
            }
        }

分析結果已經說明了問題所在,所以調試了一下程序,發現問題的根源是HttpData的Message為空,但using不會報錯坑爹啊...

public void ToProtocolData(HttpData httpbase)
        {
            httpbase.Action = Action;
            httpbase.Message = this;
            OnToProtocolData(httpbase);
            ;
        }

適當地修改一處程序問題解決.

吐能力提高但CPU占用資源過高

經過上面程序的修復4連接的秒吞吐能力由原來每秒150左右,上升到每秒2100/秒.得到的效果是非常的明顯的,但總的來說CPU占用資源還有點過高,為了驗證上一次修復的問題又進行了一次內存分析,分析的結果如下:

分析說明了一個問題由於Assembly.GetName()導致了大量的string創建,代碼如下:

value = string.Format("{0},{1}={2}", type.FullName, type.Assembly.GetName().Name, JsonConvert.SerializeObject(Message));

適當地修改一下

        value = string.Format("{0}={1}", GetTypeName(type), JsonConvert.SerializeObject(Message));

        private static System.Collections.Hashtable mNames = new System.Collections.Hashtable(1024);

        private static string GetTypeName(Type type)
        {
            string name = (string)mNames[type];
            if (name == null)
            {
                lock (mNames)
                {
                    name = (string)mNames[type];
                    if (name == null)
                    {
                        name = string.Format("{0},{1}", type.FullName, type.Assembly.GetName().Name);
                        mNames[type] = name;
                    }
                }
            }
            return name;
        }

經過以上的進一步優化后,服務的效果算是比較理想,完全滿足了現階段的需要.

意外的發現

從測試分析的結果看來,Newtonsoft.Json這個組件還有針對性優化的空間

針對以上分析,Newtonsoft.Json存在的問題應該如何優化,那就要留大家思考了.

總結

其實很多朋友喜歡通過CPU計時來看程序的快慢,但得到的結果只能說明問題,但對於如何解決這些問題,測試運行時間的結果似乎起不到什么作用.其實.NET程序有一個東西往往沒有得到關注,MS在一些文檔中要強調我們沒有必要關心,這個東西其實就是GC!的確我們對GC的工作直接可控性是沒有,但有一點可以肯定的就是GC的工作由對象的創建導致,如果想控制GC我們最好是從設計層面上控制對象的創建,這是最直接有效的辦法.


免責聲明!

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



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