洱源县建设局门户网站,百度小程序异常怎么办,wordpress增加用户组,谷歌推广培训机构一直以来用WPF做一个项目#xff0c;但是开发中途发现内存开销太大#xff0c;用ANTS Memory Profiler分析时#xff0c;发现在来回点几次载入页面的操作中#xff0c;使得非托管内存部分开销从起始的43.59M一直到150M#xff0c;而托管部分的开销也一直持高不下#xff…一直以来用WPF做一个项目但是开发中途发现内存开销太大用ANTS Memory Profiler分析时发现在来回点几次载入页面的操作中使得非托管内存部分开销从起始的43.59M一直到150M而托管部分的开销也一直持高不下即每次申请的内存在结束后不能完全释放。在网上找了不少资料甚受益现在修改后再也不会出现这种现象了或者说即使有也不吓人写下几个小心得 1. 慎用WPF样式模板合并 我发现不采用合并时非托管内存占用率较小只是代码的理解能力较差了不过我们还有文档大纲可以维护。 2. WPF样式模板请共享 共享的方式最简单不过的就是建立一个类库项目把样式、图片、笔刷什么的都扔进去样式引用最好使用StaticResource开销最小但这样就导致了一些写作时的麻烦即未定义样式就不能引用样式哪怕定义在后引用在前都不行。 3. 慎用隐式类型var的弱引用 这个本来应该感觉没什么问题的可是不明的是在实践中发现大量采用var与老老实实的使用类型声明的弱引用对比总是产生一些不能正确回收的WeakRefrense这点有待探讨因为开销不是很大可能存在一些手工编程的问题 4. 写一个接口约束一下 谁申请谁释放基本上这点能保证的话内存基本上就能释放干净了。我是这么做的 interface IUIElement : IDisposable {/// summary/// 注册事件/// /summary void EventsRegistion();/// summary/// 解除事件注册/// /summary void EventDeregistration(); } 在实现上可以这样 1 #region IUIElement 成员 2 public void EventsRegistion() 3 { 4 this.traineeReport.SelectionChanged new SelectionChangedEventHandler(traineeReport_SelectionChanged); 5 } 6 7 public void EventDeregistration() 8 { 9 this.traineeReport.SelectionChanged - new SelectionChangedEventHandler(traineeReport_SelectionChanged);10 }11 12 private bool disposed;13 14 ~TraineePaymentMgr()15 {16 ConsoleEx.Log({0}被销毁, this);17 Dispose(false);18 }19 20 public void Dispose()21 {22 ConsoleEx.Log({0}被手动销毁, this);23 Dispose(true);24 GC.SuppressFinalize(this);25 }26 27 protected void Dispose(bool disposing)28 {29 ConsoleEx.Log({0}被自动销毁, this);30 if(!disposed)31 {32 if(disposing)33 {34 //托管资源释放35 ((IDisposable)traineeReport).Dispose();36 ((IDisposable)traineePayment).Dispose();37 }38 //非托管资源释放39 }40 disposed true;41 }42 #endregion 比如写一个UserControl或是一个Page时可以参考以上代码实现这样接口有利于资源释放。 5. 定时回收垃圾 DispatcherTimer GCTimer new DispatcherTimer();public MainWindow(){ InitializeComponent();this.GCTimer.Interval TimeSpan.FromMinutes(10); //垃圾释放定时器 我定为每十分钟释放一次大家可根据需要修改 this.GCTimer.start();this.EventsRegistion(); // 注册事件}public void EventsRegistion(){this.GCTimer.Tick new EventHandler(OnGarbageCollection);}public void EventDeregistration(){this.GCTimer.Tick - new EventHandler(OnGarbageCollection);}void OnGarbageCollection(object sender, EventArgs e){ GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect();} 6. 较简单或可循环平铺的图片用GeometryDrawing实现 一个图片跟几行代码相比哪个开销更少肯定不用多说了而且这几行代码还可以BaseOn进行重用。 DrawingGroup x:KeyDiagonal_50pxDrawingGroup.ChildrenGeometryDrawing Brush#FF2A2A2A GeometryF1 M 0,0L 50,0L 50,50L 0,50 Z/GeometryDrawing Brush#FF262626 GeometryF1 M 50,0L 0,50L 0,25L 25,0L 50,0 Z/GeometryDrawing Brush#FF262626 GeometryF1 M 50,25L 50,50L 25,50L 50,25 Z//DrawingGroup.Children/DrawingGroup 这边是重用 DrawingBrush x:KeyFrameListMenuArea_Brush StretchFill TileModeTile Viewport0,0,50,50 ViewportUnitsAbsolute Drawing{StaticResource Diagonal_50px}/ 上面几行代码相当于这个 7. 使用Blend做样式的时候一定要检查完成的代码 众所周知Blend定义样式时产生的垃圾代码还是比较多的如果使用Blend一定要检查生成的代码。 8. 静态方法返回诸如List等变量的请使用out 比如 public static ListString myMothod(){...} 请改成 public static myMothod(out ListString result){...} 9. 打针对此问题的微软补丁 3.5的应该都有了吧这里附上NET4的内存泄露补丁地址下载点这里 QFE: Hotfix request to implement hotfix KB981107 in .NET 4.0 这是官方给的说明看来在样式和数据绑定部分下了点工夫啊 运行一个包含样式或模板请参阅通过使用 StaticResource 标记扩展或 DynamicResource 标记扩展应用程序资源的 WPF 应用程序。 创建使用这些样式或模板的多个控件。 但是这些控件不使用引用的资源。 在这种情况的一些内存WeakReference对象和空间泄漏的控股数组后垃圾回收释放该控件。运行一个包含的控件的属性是数据绑定到的 WPF 应用程序DependencyObject对象。 该对象的生存期是超过控件的生存期。 许多控件时创建一些内存WeakReference对象和容纳数组空格被泄漏后垃圾回收释放该控件。运行使用树视图控件或控件派生于的 WPF 应用程序选择器类。 将控件注册为控制中的键盘焦点的内部通知在KeyboardNavigation类。 该应用程序创建这些控件的很多。 例如对于您添加并删除这些控件。 在本例中为某些内存WeakReference对象和容纳数组空格被泄漏后垃圾回收释放该控件。继续更新有关的三个8月补丁详细的请百度KB2487367 KB2539634 KB2539636都是NET4的补丁在发布程序的时候把这些补丁全给客户安装了会好的多。 10. 对string怎么使用的建议 这个要解释话就长了下面仅给个例子说明一下具体的大家去找找MSDN string ConcatString(params string[] items) {string result ;foreach (string item in items) { result item; }return result; }string ConcatString2(params string[] items) { StringBuilder result new StringBuilder();for(int i0, count items.Count(); icount; i) { result.Append(items[i]); }return result.ToString(); } 建议在需要对string进行多次更改时循环赋值、连接之类的使用StringBuilder。我已经把工程里这种频繁且大量改动string的操作全部换成了StringBuilder了用ANTS Memory Profiler分析效果显著不仅提升了性能而且垃圾也少了。 11. 其它用上的技术暂时还没想到再补充... 如果严格按以上操作进行的话可以得到一个满意的结果 运行了三十分钟不断的切换功能然后休息5分钟回头一看结果才17M左右内存开销效果显著吧。 然后对于调试信息的输出我的做法是在窗体应用程序中附带一个控制台窗口输出调试信息给一个类方便大家 using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Runtime.InteropServices;namespace Trainee.UI.UIHelper{public struct COORD {public ushort X;public ushort Y; };public struct CONSOLE_FONT {public uint index;public COORD dim; };public static class ConsoleEx { [System.Security.SuppressUnmanagedCodeSecurity] [DllImport(kernel32, CharSet CharSet.Auto)]internal static extern bool AllocConsole(); [System.Security.SuppressUnmanagedCodeSecurity] [DllImport(kernel32, CharSet CharSet.Auto)]internal static extern bool SetConsoleFont(IntPtr consoleFont, uint index); [System.Security.SuppressUnmanagedCodeSecurity] [DllImport(kernel32, CharSet CharSet.Auto)]internal static extern bool GetConsoleFontInfo(IntPtr hOutput, byte bMaximize, uint count, [In, Out] CONSOLE_FONT[] consoleFont); [System.Security.SuppressUnmanagedCodeSecurity] [DllImport(kernel32, CharSet CharSet.Auto)]internal static extern uint GetNumberOfConsoleFonts(); [System.Security.SuppressUnmanagedCodeSecurity] [DllImport(kernel32, CharSet CharSet.Auto)]internal static extern COORD GetConsoleFontSize(IntPtr HANDLE, uint DWORD); [System.Security.SuppressUnmanagedCodeSecurity] [DllImport(kernel32.dll )]internal static extern IntPtr GetStdHandle(int nStdHandle); [System.Security.SuppressUnmanagedCodeSecurity] [DllImport(kernel32.dll, CharSet CharSet.Auto, SetLastError true)]internal static extern int GetConsoleTitle(String sb, int capacity); [System.Security.SuppressUnmanagedCodeSecurity] [DllImport(user32.dll, EntryPoint UpdateWindow)]internal static extern int UpdateWindow(IntPtr hwnd); [System.Security.SuppressUnmanagedCodeSecurity] [DllImport(user32.dll)]internal static extern IntPtr FindWindow(String sClassName, String sAppName);public static void OpenConsole() { var consoleTitle Debug Console; AllocConsole(); Console.BackgroundColor ConsoleColor.Black; Console.ForegroundColor ConsoleColor.Cyan; Console.WindowWidth 80; Console.CursorVisible false; Console.Title consoleTitle; Console.WriteLine(DEBUG CONSOLE WAIT OUTPUTING...{0} {1}\n, DateTime.Now.ToLongTimeString());try {//这里是改控制台字体大小的可能会导致异常在我这个项目中我懒得弄了如果需要的的话把注释去掉就行了//IntPtr hwnd FindWindow(null, consoleTitle);//IntPtr hOut GetStdHandle(-11);//const uint MAX_FONTS 40;//uint num_fonts GetNumberOfConsoleFonts();//if (num_fonts MAX_FONTS) num_fonts MAX_FONTS;//CONSOLE_FONT[] fonts new CONSOLE_FONT[MAX_FONTS];//GetConsoleFontInfo(hOut, 0, num_fonts, fonts);//for (var n 7; n num_fonts; n)//{// //fonts[n].dim GetConsoleFontSize(hOut, fonts[n].index);// //if (fonts[n].dim.X 106 fonts[n].dim.Y 33)// //{// SetConsoleFont(hOut, fonts[n].index);// UpdateWindow(hwnd);// return;// //}//} }catch { } }public static void Log(String format, params object[] args) { Console.WriteLine([ DateTime.Now.ToLongTimeString() ] format, args); }public static void Log(Object arg) { Console.WriteLine(arg); } }} 在程序启动时可以用ConsoleEx.OpenConsole()打开控制台用ConsoleEx.Log(.....)或者干脆用Console.WriteLine进行输出就可以了。转载于:https://www.cnblogs.com/LastPropose/archive/2011/08/01/2124359.html