項(xiàng)目中使用微軟RDLC生成工作票去打印,但是RDLC存在著嚴(yán)重的內(nèi)存泄露問(wèn)題。在生產(chǎn)高峰時(shí)期,工人將大量的工作票請(qǐng)求發(fā)送到服務(wù)器,隨著工作票的生成內(nèi)存就一點(diǎn)點(diǎn)的被吃掉。致使IT部門不得不為一個(gè)小小的工作票服務(wù)準(zhǔn)備一臺(tái)8G內(nèi)存的服務(wù)器,并且定期的查看服務(wù)狀態(tài)。在生產(chǎn)高峰時(shí)期每小時(shí)都要重啟。
成都創(chuàng)新互聯(lián)公司從2013年開(kāi)始,先為建始等服務(wù)建站,建始等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為建始企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。這個(gè)內(nèi)存泄露問(wèn)題自從VS2005以來(lái)就存在,微軟聲稱在2008 SP1中已經(jīng)修正,但是項(xiàng)目中使用的是2010的程序集版本且問(wèn)題依然很嚴(yán)重。從微軟官方的回復(fù)看由于RDLC使用VB進(jìn)行表達(dá)式的計(jì)算,加載的VB相關(guān)的程序集由于某些原因不被Unload。我想微軟在VS2008SP1中修正的應(yīng)該是這個(gè)問(wèn)題,當(dāng)然我沒(méi)有去考證,但是可以肯定的是在VS2010的RDLC中還是有內(nèi)存泄露的代碼存在。
網(wǎng)友還做過(guò)測(cè)試,如果不使用Expression就不會(huì)導(dǎo)致內(nèi)存泄露,但是我并不想修改太多的程序,如果你的項(xiàng)目剛剛開(kāi)始或并不復(fù)雜,這也是一個(gè)辦法。參見(jiàn)原文:http://blog.darkthread.net/post-2012-01-12-rdlc-out-of-memory.aspx
于是著手從網(wǎng)上搜索如何查找內(nèi)存泄露,推薦一個(gè)工具給大家。.Net Memory Profile http://memprofiler.com/. 這個(gè)工具可以分析出內(nèi)存中哪些對(duì)象已經(jīng)GC但是沒(méi)有被成功的移除或移除的不夠徹底。通過(guò)個(gè)這工具分析出LocalReport中的方法被事件或代理對(duì)象所引用無(wú)法GC。如下圖
從上圖可以看到LocalReport的身影,這張圖中的所有對(duì)象全與RDLC有關(guān)。
在網(wǎng)上搜到一牛人用反射解決了ReportViewer的內(nèi)存泄露問(wèn)題。參見(jiàn)原貼:http://social.msdn.microsoft.com/Forums/en-US/vsreportcontrols/thread/d21f8b56-3123-4aff-bf84-9cce727bc2ce
于是我參考了這個(gè)做法結(jié)合.Net Memory Profiler的分析結(jié)果開(kāi)始將LocalReport對(duì)象上的事件和代理去掉。雖然這個(gè)方法失敗了還是把代碼貼出來(lái)吧,如下:
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元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。
文章標(biāo)題:臨時(shí)解決方案-RDLC報(bào)表內(nèi)存泄露問(wèn)題-創(chuàng)新互聯(lián)
分享鏈接:http://jinyejixie.com/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)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容