MVC+MEF+UnitOfWork+EF架構,網站速度慢的緣由總結!(附加ANTS Memory Profiler簡單用法)

(最近使用內存分析工具ANTS Memory Profiler,以及其餘網友提供的意見發現最終致使內存泄漏的就是MEF,在此特意更新下,與你們分享!最下面紅色字體)html

最近參考使用了郭明峯的一套架構來作新的項目架構,這套架構看起來仍是不錯的,先向小郭同窗的分享精神致敬!sql

郭同窗的項目文檔:http://www.cnblogs.com/guomingfeng/archive/2013/05/19/mvc-overall-design.html架構

項目開發上線後,傻眼了,貌似沒有幾我的訪問的新項目,速度一直慢的跟牛同樣,真心無法交差啊。上面發下話了,解決不了就能夠走人了。壓力可想而知。mvc

接下來就是苦逼的找緣由了。工具

症狀:一、內存佔用高,8g的內存很快就能吃完性能

         二、網站相應速度慢,firebug檢測每次都是在等待學習

根據這些症狀,感受是內存泄露了,因而memory profiler。。。什麼性能分析工具都用上了,怎奈水平有限,不會使用這些高級玩意,一番折騰下來,就剩下無奈。測試

但總不能放棄,對比以前作的mvc項目,就是多了entityframework、MEF這兩樣,看樣子也就這兩塊的緣由了,EF的嫌疑最大,並且首次使用,並不瞭解。因而,接下來又是一段苦逼的研究;功夫不負有心人,根據目前研究的結果及上線的效果來看,基本上找到了問題的所在。總結下,與諸位分享,高手忽略。字體

問題緣由:一、不少數據查詢一次性讀入到內存中,致使內存增長。優化

               二、上下文對讀入到內存中的數據對象會進行跟蹤,致使內存不斷攀升,疑似內存泄露

解決辦法:一、深刻學習EF,監控每一步生成的sql語句,防止無用數據的調取

               二、網站大部分的數據在讀取的時候是不須要進行上下文跟蹤的,必定要禁止跟蹤,不然內存就會爆了!代碼以下:

/// <summary>
        /// 獲取當前實體的查詢數據集(經過讀上下文進行讀取,只讀專用,返回的實體數據不會被上下文跟蹤)
        /// </summary>
        public virtual IQueryable<TEntity> ReadEntities
        {
            get { return WriteContext.Set<TEntity>().AsNoTracking(); }
        }

        /// <summary>
        /// 獲取當前實體的查詢數據集(經過寫上下文進行讀取,修改專用,返回的實體數據會被上下文進行跟蹤)
        /// </summary>
        public virtual IQueryable<TEntity> WriteEntities
        {
            get { return WriteContext.Set<TEntity>(); }
        }

說明:我在倉儲模式中,對讀取實體集合進行了修改,ReadEntities表示不須要進行跟蹤的,加上AsNoTracking方法;WriteEntities表示是須要跟蹤的,用於修改實體信息使用。這樣以來,全部的症狀所有消失了。

固然,也許有更好的優化方法,至少目前本人發現了這些問題所在,並且微軟的白皮書中確實也講的了EF的性能注意事項,怎奈倉促開發,對EF絕不瞭解,罪過罪過!你們引覺得鑑!

 

另外,還遇到一個問題,不知道是不是DBcontext線程衝突問題,你們幫分析下,謝謝:

 

    持續的內存泄漏問題終於有告終果了,花了近一週的時間,無數苦逼的熬夜,終於掌握了ANTS Memory Profiler的基本用法,結合以前網友的寶貴意見,經檢測,終於發現致使內存泄漏的罪魁禍首:MEF。

小郭的架構中有這麼一段代碼:

        public CompositionContainer Container
        {
            get
            {
                CompositionContainer container;
                if (!HttpContext.Current.Items.Contains(MefContainerKey))
                {
                    container = new CompositionContainer(_catalog, CompositionOptions.DisableSilentRejection);
                    HttpContext.Current.Items.Add(MefContainerKey, container);
HttpContext.Current.DisposeOnPipelineCompleted(container); }
else { container = (CompositionContainer)HttpContext.Current.Items[MefContainerKey]; } return container; } }

這段代碼用於建立MEF容器,並向其中加入對象實例化的目錄。

小郭童鞋說了,項目中的全部Import的對象都是MEF建立的,不須要刻意的去Dispose,只要MEF對象釋放了,那麼container中的全部實例化對象就會被釋放。

話沒錯,但代碼中確實沒有看到有釋放container對象的地方,我翻遍了評論,看到有個哥們ltcszk提醒說要加入HttpContext.Current.DisposeOnPipelineCompleted(container)這句話就ok,當時並未重視,執拗的認爲是過多的DBContext致使的,這兩天通過ANTS Memory Profiler測試下,果然是這個問題致使的,加上這句話,效果立竿見影,在此感謝ltcszk的提醒。同時總結下,與諸位分享!

 

在頁面打開後,理論上此次請求就完畢,全部線程中建立的對象就應該被GC釋放掉,Profiler在每次快照的時候就會執行GC的回收,那麼實際的狀況咱們看下

優化前:

內存情況:

第一步

第二步

第三步

 

優化後:

駐留在內存中的類型明顯少了不少,只有35個,大部分是cache內容!

在此記錄,與諸位分享,歡迎拍磚!

相關文章
相關標籤/搜索