臨時解決方案-RDLC報表內(nèi)存泄露問題-創(chuàng)新互聯(lián)

項(xiàng)目中使用微軟RDLC生成工作票去打印,但是RDLC存在著嚴(yán)重的內(nèi)存泄露問題。在生產(chǎn)高峰時期,工人將大量的工作票請求發(fā)送到服務(wù)器,隨著工作票的生成內(nèi)存就一點(diǎn)點(diǎn)的被吃掉。致使IT部門不得不為一個小小的工作票服務(wù)準(zhǔn)備一臺8G內(nèi)存的服務(wù)器,并且定期的查看服務(wù)狀態(tài)。在生產(chǎn)高峰時期每小時都要重啟。

成都創(chuàng)新互聯(lián)公司從2013年開始,先為建始等服務(wù)建站,建始等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為建始企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。

這個內(nèi)存泄露問題自從VS2005以來就存在,微軟聲稱在2008 SP1中已經(jīng)修正,但是項(xiàng)目中使用的是2010的程序集版本且問題依然很嚴(yán)重。從微軟官方的回復(fù)看由于RDLC使用VB進(jìn)行表達(dá)式的計算,加載的VB相關(guān)的程序集由于某些原因不被Unload。我想微軟在VS2008SP1中修正的應(yīng)該是這個問題,當(dāng)然我沒有去考證,但是可以肯定的是在VS2010的RDLC中還是有內(nèi)存泄露的代碼存在。

網(wǎng)友還做過測試,如果不使用Expression就不會導(dǎo)致內(nèi)存泄露,但是我并不想修改太多的程序,如果你的項(xiàng)目剛剛開始或并不復(fù)雜,這也是一個辦法。參見原文:http://blog.darkthread.net/post-2012-01-12-rdlc-out-of-memory.aspx

于是著手從網(wǎng)上搜索如何查找內(nèi)存泄露,推薦一個工具給大家。.Net Memory Profile http://memprofiler.com/. 這個工具可以分析出內(nèi)存中哪些對象已經(jīng)GC但是沒有被成功的移除或移除的不夠徹底。通過個這工具分析出LocalReport中的方法被事件或代理對象所引用無法GC。如下圖

臨時解決方案 - RDLC報表內(nèi)存泄露問題

從上圖可以看到LocalReport的身影,這張圖中的所有對象全與RDLC有關(guān)臨時解決方案 - RDLC報表內(nèi)存泄露問題。

在網(wǎng)上搜到一牛人用反射解決了ReportViewer的內(nèi)存泄露問題。參見原貼:http://social.msdn.microsoft.com/Forums/en-US/vsreportcontrols/thread/d21f8b56-3123-4aff-bf84-9cce727bc2ce

于是我參考了這個做法結(jié)合.Net Memory Profiler的分析結(jié)果開始將LocalReport對象上的事件和代理去掉。雖然這個方法失敗了還是把代碼貼出來吧,如下:

using System;
using System.Reflection;
using System.Linq;
using System.Windows.Forms;
using Microsoft.Reporting.WinForms;
using Microsoft.Win32;
using System.Collections;
namespace TOG.ProductionOutput.Services
{
    public class LocalReportDisposer : IDisposable
    {
        // Fields
        private bool _CollectGarbageOnDispose = false;
        private LocalReport localReport;
        private bool disposedValue = false;
        private const string LOCALREPORT_DATASOURCES = "m_dataSources";
        private const string LOCALREPORT_PROCESSINGHOST = "m_processingHost";
        private const string PROCESSINGHOST_DATARETRIEVAL = "m_dataRetrieval";
        private const string DATARETRIEVAL_SUBREPORTDATACALLBACK = "m_subreportDataCallback";
        private const string SUBREPORTDATACALLBACK_TARGET = "_target";
        private const string PROCESSINGHOST_EXECUTIONSESSION = "m_executionSession";
        private const string EXECUTIONSESSION_COMPILEDREPORT = "__compiledReport";
        private const string EXECUTIONSESSION_REPORTSNAPSHOT = "__ReportSnapshot";
        private const string DATASOURCES_ONCHANGE = "OnChange";
        // Methods
        public LocalReportDisposer(LocalReport localReport)
        {
            if (localReport == null)
            {
                throw new ArgumentNullException("ReportViewer cannot be null.");
            }
            this.localReport = localReport;
        }
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposedValue && disposing)
            {
                //this.TearDownLocalReport();
                this.localReport.Dispose();
                if (this._CollectGarbageOnDispose)
                {
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                    GC.Collect();
                }
            }
            this.disposedValue = true;
        }
        private void TearDownLocalReport()
        {
            Type t = this.localReport.GetType();
            //localReport.m_dataSources
            FieldInfo fi = t.GetField(LOCALREPORT_DATASOURCES, BindingFlags.NonPublic | BindingFlags.Instance);
            object dataSources = fi.GetValue(this.localReport);
            //remove event from localReport.m_dataSources.Change
            ReflectUtil.RemoveEventHandlersFrom(
                delegate(Delegate subject) { return subject.Method.Name == DATASOURCES_ONCHANGE; },
                dataSources);
            //localReport.m_processingHost
            fi = t.GetField(LOCALREPORT_PROCESSINGHOST, BindingFlags.NonPublic | BindingFlags.Instance);
            object processingHost = fi.GetValue(this.localReport);
            //localReport.m_processingHost.dataretrieval
            t = processingHost.GetType().BaseType;
            fi = t.GetField(PROCESSINGHOST_DATARETRIEVAL, BindingFlags.NonPublic | BindingFlags.Instance);
            object dataRetrieval = fi.GetValue(processingHost);
            //localReport.m_processingHost.m_dataRetrieval.m_subreportDataCallback
            t = dataRetrieval.GetType();
            fi = t.GetField(DATARETRIEVAL_SUBREPORTDATACALLBACK, BindingFlags.NonPublic | BindingFlags.Instance);
            object subReportDataCallBack = fi.GetValue(dataRetrieval);
            //localReport.m_processingHost.m_dataRetrieval.m_subreportDataCallback._target
            t = subReportDataCallBack.GetType().BaseType.BaseType;
            fi = t.GetField(SUBREPORTDATACALLBACK_TARGET, BindingFlags.NonPublic | BindingFlags.Instance);
            fi.SetValue(subReportDataCallBack, null);
            t = processingHost.GetType().BaseType;
            fi = t.GetField(PROCESSINGHOST_EXECUTIONSESSION, BindingFlags.NonPublic | BindingFlags.Instance);
            object executionSession = fi.GetValue(processingHost);
            t = executionSession.GetType();
            fi = t.GetField(EXECUTIONSESSION_COMPILEDREPORT, BindingFlags.NonPublic | BindingFlags.Instance);
            IDisposable report = fi.GetValue(executionSession) as IDisposable;
            if (report != null) report.Dispose();
            fi = t.GetField(EXECUTIONSESSION_REPORTSNAPSHOT, BindingFlags.NonPublic | BindingFlags.Instance);
            report = fi.GetValue(executionSession) as IDisposable;
            if (report != null) report.Dispose();
        }
        // Properties
        public bool CollectGarbageOnDispose
        {
            get
            {
                return this._CollectGarbageOnDispose;
            }
            set
            {
                this._CollectGarbageOnDispose = value;
            }
        }
    }
}
using System;using System.Reflection;using System.Linq;using System.Windows.Forms;  using Microsoft.Reporting.WinForms;  using Microsoft.Win32;using System.Collections;namespace TOG.ProductionOutput.Services{publicclass LocalReportDisposer : IDisposable   {// Fields  privatebool _CollectGarbageOnDispose = false;private LocalReport localReport;privatebool disposedValue = false;privateconststring LOCALREPORT_DATASOURCES = "m_dataSources";privateconststring LOCALREPORT_PROCESSINGHOST = "m_processingHost";privateconststring PROCESSINGHOST_DATARETRIEVAL = "m_dataRetrieval";privateconststring DATARETRIEVAL_SUBREPORTDATACALLBACK = "m_subreportDataCallback";privateconststring SUBREPORTDATACALLBACK_TARGET = "_target";privateconststring PROCESSINGHOST_EXECUTIONSESSION = "m_executionSession";privateconststring EXECUTIONSESSION_COMPILEDREPORT = "__compiledReport";privateconststring EXECUTIONSESSION_REPORTSNAPSHOT = "__ReportSnapshot";privateconststring DATASOURCES_ONCHANGE = "OnChange";// Methods  public LocalReportDisposer(LocalReport localReport)     {if (localReport == null)       {thrownew ArgumentNullException("ReportViewer cannot be null.");       }this.localReport = localReport;     }publicvoid Dispose()     {this.Dispose(true);       GC.SuppressFinalize(this);     }protectedvirtualvoid Dispose(bool disposing)     {if (!this.disposedValue && disposing)       {//this.TearDownLocalReport();this.localReport.Dispose();if (this._CollectGarbageOnDispose)         {           GC.Collect();           GC.WaitForPendingFinalizers();           GC.Collect();         }       }this.disposedValue = true;     }privatevoid TearDownLocalReport()     {       Type t = this.localReport.GetType();//localReport.m_dataSourcesFieldInfo fi = t.GetField(LOCALREPORT_DATASOURCES, BindingFlags.NonPublic | BindingFlags.Instance);object dataSources = fi.GetValue(this.localReport);//remove event from localReport.m_dataSources.ChangeReflectUtil.RemoveEventHandlersFrom(delegate(Delegate subject) { return subject.Method.Name == DATASOURCES_ONCHANGE; },         dataSources);//localReport.m_processingHostfi = t.GetField(LOCALREPORT_PROCESSINGHOST, BindingFlags.NonPublic | BindingFlags.Instance);object processingHost = fi.GetValue(this.localReport);//localReport.m_processingHost.dataretrievalt = processingHost.GetType().BaseType;       fi = t.GetField(PROCESSINGHOST_DATARETRIEVAL, BindingFlags.NonPublic | BindingFlags.Instance);object dataRetrieval = fi.GetValue(processingHost);//localReport.m_processingHost.m_dataRetrieval.m_subreportDataCallbackt = dataRetrieval.GetType();       fi = t.GetField(DATARETRIEVAL_SUBREPORTDATACALLBACK, BindingFlags.NonPublic | BindingFlags.Instance);object subReportDataCallBack = fi.GetValue(dataRetrieval);//localReport.m_processingHost.m_dataRetrieval.m_subreportDataCallback._targett = subReportDataCallBack.GetType().BaseType.BaseType;       fi = t.GetField(SUBREPORTDATACALLBACK_TARGET, BindingFlags.NonPublic | BindingFlags.Instance);       fi.SetValue(subReportDataCallBack, null);       t = processingHost.GetType().BaseType;       fi = t.GetField(PROCESSINGHOST_EXECUTIONSESSION, BindingFlags.NonPublic | BindingFlags.Instance);object executionSession = fi.GetValue(processingHost);       t = executionSession.GetType();       fi = t.GetField(EXECUTIONSESSION_COMPILEDREPORT, BindingFlags.NonPublic | BindingFlags.Instance);       IDisposable report = fi.GetValue(executionSession) as IDisposable;if (report != null) report.Dispose();       fi = t.GetField(EXECUTIONSESSION_REPORTSNAPSHOT, BindingFlags.NonPublic | BindingFlags.Instance);       report = fi.GetValue(executionSession) as IDisposable;if (report != null) report.Dispose();     }// Properties  publicbool CollectGarbageOnDispose     {get{returnthis._CollectGarbageOnDispose;       }set{this._CollectGarbageOnDispose = value;       }     }   }}
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
namespace TOG.ProductionOutput.Services
{
    public sealed class ReflectUtil
    {
        private static BindingFlags PrivatePublicStaticInstance
          = BindingFlags.NonPublic | BindingFlags.Public |
            BindingFlags.Instance | BindingFlags.Static;
        public delegate bool MatchesOnDelegate(Delegate subject);
        public static void RemoveEventHandlersFrom(
          MatchesOnDelegate matchesOnDelegate, params object[] objectsWithEvents)
        {
            foreach (object owningObject in objectsWithEvents)
            {
                foreach (DelegateInfo eventFromOwningObject in GetDelegates(owningObject))
                {
                    foreach (Delegate subscriber in eventFromOwningObject.GetInvocationList())
                    {
                        if (matchesOnDelegate(subscriber))
                        {
                            EventInfo theEvent = eventFromOwningObject.GetEventInfo();
                            if(theEvent != null)
                                RemoveSubscriberEvenIfItsPrivate(theEvent, owningObject, subscriber);
                        }
                    }
                }
            }
        }
        // You can use eventInfo.RemoveEventHandler(owningObject, subscriber)
        // unless it's a private delegate
        private static void RemoveSubscriberEvenIfItsPrivate(
          EventInfo eventInfo, object owningObject, Delegate subscriber)
        {
            MethodInfo privateRemoveMethod = eventInfo.GetRemoveMethod(true);
            privateRemoveMethod.Invoke(owningObject,
                                       PrivatePublicStaticInstance, null,
                                       new object[] { subscriber }, CultureInfo.CurrentCulture);
        }
        private static DelegateInfo[] GetDelegates(object owningObject)
        {
            List<DelegateInfo> delegates = new List<DelegateInfo>();
            FieldInfo[] allPotentialEvents = owningObject.GetType()
              .GetFields(PrivatePublicStaticInstance);
            foreach (FieldInfo privateFieldInfo in allPotentialEvents)
            {
                Delegate eventFromOwningObject = privateFieldInfo.GetValue(owningObject)
                  as Delegate;
                if (eventFromOwningObject != null)
                {
                    delegates.Add(new DelegateInfo(eventFromOwningObject, privateFieldInfo,
                      owningObject));
                }
            }
            return delegates.ToArray();
        }
        private class DelegateInfo
        {
            private readonly Delegate delegateInformation;
            public Delegate DelegateInformation
            {
                get { return delegateInformation; }
            }
            private readonly FieldInfo fieldInfo;
            private readonly object owningObject;
            public DelegateInfo(Delegate delegateInformation, FieldInfo fieldInfo,
              object owningObject)
            {
                this.delegateInformation = delegateInformation;
                this.fieldInfo = fieldInfo;
                this.owningObject = owningObject;
            }
            public Delegate[] GetInvocationList()
            {
                return delegateInformation.GetInvocationList();
            }
            public EventInfo GetEventInfo()
            {
                return owningObject.GetType().GetEvent(fieldInfo.Name,
                  PrivatePublicStaticInstance);
            }
        }
    }
}
using System;using System.Collections.Generic;using System.Globalization;using System.Reflection;namespace TOG.ProductionOutput.Services{publicsealedclass ReflectUtil   {privatestatic BindingFlags PrivatePublicStaticInstance      = BindingFlags.NonPublic | BindingFlags.Public |       BindingFlags.Instance | BindingFlags.Static;publicdelegatebool MatchesOnDelegate(Delegate subject);publicstaticvoid RemoveEventHandlersFrom(      MatchesOnDelegate matchesOnDelegate, paramsobject[] objectsWithEvents)     {foreach (object owningObject in objectsWithEvents)       {foreach (DelegateInfo eventFromOwningObject in GetDelegates(owningObject))         {foreach (Delegate subscriber in eventFromOwningObject.GetInvocationList())           {if (matchesOnDelegate(subscriber))             {               EventInfo theEvent = eventFromOwningObject.GetEventInfo();if(theEvent != null)                 RemoveSubscriberEvenIfItsPrivate(theEvent, owningObject, subscriber);             }           }         }       }     }// You can use eventInfo.RemoveEventHandler(owningObject, subscriber) // unless it's a private delegateprivatestaticvoid RemoveSubscriberEvenIfItsPrivate(      EventInfo eventInfo, object owningObject, Delegate subscriber)     {       MethodInfo privateRemoveMethod = eventInfo.GetRemoveMethod(true);       privateRemoveMethod.Invoke(owningObject,                    PrivatePublicStaticInstance, null,                    newobject[] { subscriber }, CultureInfo.CurrentCulture);     }privatestatic DelegateInfo[] GetDelegates(object owningObject)     {       List<DelegateInfo> delegates = new List<DelegateInfo>();       FieldInfo[] allPotentialEvents = owningObject.GetType()        .GetFields(PrivatePublicStaticInstance);foreach (FieldInfo privateFieldInfo in allPotentialEvents)       {         Delegate eventFromOwningObject = privateFieldInfo.GetValue(owningObject)          as Delegate;if (eventFromOwningObject != null)         {           delegates.Add(new DelegateInfo(eventFromOwningObject, privateFieldInfo,            owningObject));         }       }return delegates.ToArray();     }privateclass DelegateInfo     {privatereadonly Delegate delegateInformation;public Delegate DelegateInformation       {get { return delegateInformation; }       } privatereadonly FieldInfo fieldInfo;privatereadonlyobject owningObject;public DelegateInfo(Delegate delegateInformation, FieldInfo fieldInfo,        object owningObject)       {this.delegateInformation = delegateInformation;this.fieldInfo = fieldInfo;this.owningObject = owningObject;       }public Delegate[] GetInvocationList()       {return delegateInformation.GetInvocationList();       }public EventInfo GetEventInfo()       {return owningObject.GetType().GetEvent(fieldInfo.Name,          PrivatePublicStaticInstance);       }     }   }}

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。

文章標(biāo)題:臨時解決方案-RDLC報表內(nèi)存泄露問題-創(chuàng)新互聯(lián)
分享鏈接:http://muchs.cn/article6/hihig.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供虛擬主機(jī)、網(wǎng)站收錄品牌網(wǎng)站建設(shè)、手機(jī)網(wǎng)站建設(shè)、網(wǎng)站制作、用戶體驗(yàn)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)公司