《NET 内存注意事项》由会员分享,可在线阅读,更多相关《NET 内存注意事项(5页珍藏版)》请在金锄头文库上搜索。
1、.NET 内存注意事项1. 资源文件相关资源文件应用的三种方式1. 资源文件基于XML结构,有专门的编辑器,resx区别于resources文件,resx只保存对资源的应用2. WinForm 的 resx 文件和工程的 resx 文件Winform的resx和工程的resx是和form以及工程相关联的,Form.cs与form.Designer.cs 和 Form.resx 作为整体展示。使用方式:Assemblyassembly = Assembly.GetExecutingAssembly();ResourceManagerrm = newResourceManager(MemTest.
2、Form1, assembly);MessageBox.Show(rm.GetString(String1);3. 项目内嵌文件直接添加文件目录,文件将编译到DLL中,通过GetMainfestResourceStream获得流Assembly_assembly = Assembly.GetExecutingAssembly();stringresourceName = _namespace + .Images.Image1.jpg;Streamstream = _assembly.GetManifestResourceStream(resourceName);4. 外部资源直接通过流获取本机
3、磁盘文件。四种方式的比较:1. 新建资源文件,放入5MB的图片,应用程序exe对应增加为5MB使用方式:pictureBox1.Image = Resource1.Image1;第一次需要1000ms第二次需要500ms如果不通过显示的Dispose,内存即使GC也不会被回收2. 内嵌资源,直接将图片放到Form的PictureBox控件中,5MB的图片会放到Form.resx中第一次需要 1000ms第二次需要 500ms通过调用GC,可以回收内存3. 项目资源,读取工程内的内嵌资源每次运行都只需要 500msTypetype = MethodBase.GetCurrentMethod().
4、DeclaringType;string_namespace = type.Namespace;Assembly_assembly = Assembly.GetExecutingAssembly();stringresourceName = _namespace + .Images.Image1.jpg;Streamstream = _assembly.GetManifestResourceStream(resourceName);if (stream !=null)ImagemyImage = Image.FromStream(stream);this.pictureBox1.Image =
5、 myImage;stream.Close();stream.Dispose();image = Image.FromFile(filename);bitmap = newBitmap(image);4. 外部文件方式通过流直接读取磁盘文件,如果不通过Dispose,即使GC也不释放通过在窗口关闭时dispose,可以立即释放。2. St ring&S tringB uil der&字符串驻留实例化一个St ring的对象后,在内存中将为此对象分配一个空间,当修改St ring对象值 也会重新分配一个空间,样原来的内存空间就被浪费掉了,只能等待垃圾回收器回收。如果是 频繁的这样做的话,建议是使
6、用StringBuilder对象,但是如果频繁累加字符串的次数不是很 多的时候实际上用StringBuilder会适得其反。字符串拘留:字符串拘留可以减少程序中St ring对象所需要的内存总量,如果程序中有大量重复的字符串,效果将 会很明显。CLR通过维护一个表来存放字符串,该表称为拘留池,它包含程序中以编程方式声明或创建的每个唯 一的字符串的一个引用。因此,具有特定值的字符串的实例在系统中只有一个。例如,如果将同一字符串分配给几个变量,运行库就会从拘留池中检索对该字符串的相同引用,并将 它分配给各个变量。字符串驻留函数体通过检索系统对指定St ring的引用,如果存在这样的字符串,那么便返
7、 回他的引用,否则便创建一个新的字符串,然后返回他的引用。3. 弱引用(WeakReference)一般认为在应用程序执行期间,对象在任意时刻要么是活动的,即表示应用程序有指向对 象的引用;要么对象是非活动的。当应用程序释放了指向对象的最后一个引用后,对象就从活 动状态变为不活动状态了。对象在“活动状态”和“非活动状态”之间还有一个第三种状态。 如果对象处在这种状态下,应用程序可以访问对象,而CLR的垃圾收集器(GC)也可以随时释放 对象,这就是弱引用。一般认为当满足下列条件时,就应该考虑使用弱引用: 对象稍后可能被使用,但不是很确定。(如果确定要使用,就应该用强引用) 如果需要,对象可以重新
8、被构造出来(比如数据库构造)。 对象占相对比较大的内存(一般大于几KB以上)ASP.NET的高速缓存(System.Web.Cache)就是运用的弱引用机制,另外对于GDI绘图,因为操 作系统是不允许GDI的Handle大于9999,但GDI绘图完毕后需要删除掉,以防止DI泄漏,由于大 多数绘图句柄是可以重用的,可以通过建立GDI的Handle句柄弱引用缓存来提高性能。4. 池机制首先看一段代码:while (IsRecordAvailable()PatientRecord record = GetNextRecord();. / 处理在这个循环中,每次这个循环执行时返回一个新的Pat ien
9、 tRecord对象。非常明显:Get Nex tRecord方法的执行将在它每次被调用时将创建一个新对象,并要求对象被配置,初始化, 甚至垃圾收集,和析构如果这个对象有一个完成器(finalizer)。当使用一个对象池,配置, 初始化,收集和析构只发生一次,既减少了内存使用又减少所需的运行时间。再看下一段代码:PatientRecord record = new PatientRecord();while (IsRecordAvailable()record.Clear();FillNextRecord(record);. /处理单个Pat ien tRecord对象被创建并且一个Clear
10、方法使内容复位以使其可以在循环内重复使用。 FillNex tRecord方法使用了一个现有对象,避免重复配置新的对象。当然,你仍要在每次这个 代码段执行时为单个分配、初始化、收集而消耗资源(尽管这仍比每次循环的消耗要好得多)。 如果初始化消耗甚多,或同时有多个线程调用代码,重复创建的效果可能仍是个问题。 对象池机制的基本模式看起来就像这样:while (IsRecordAvailable()PatientRecord record = Pool.GetObject();record.Clear();FillNextRecord(record);. /处理Pool.ReleaseObject(
11、record);一个Pat ien tRecord实例,或实例池,在应用程序的开始被创建。代码从池中重新得到一个实例, 避免了内存分配,构建,和最后的垃圾收集。这个过程是节省了大量的时间和内存。5. 大对象堆NET的大对象堆是专门存放大于85,000bytes字节对象,并且不受空间限制,直至Out of Memory。 大对象的不断分配会造成内存碎片,应尽量减少应用大对象堆。大对象堆使用的最坏情况的场景如下图:-ree ( 6MB5Allouilincw65kHI tap CKpandl1Garbaje cdlecied85No space!SS16. IMSFree審 new block (end of heap pneferrerf)6. 动态编译 CodeDOM运用CodeDom进行动态编译会造成内存的浪费。1. 小于64KB的assembly会被加载到64KB的段中,而多余48KB地址空间将会被浪费,并造成内 存空间不连续,导致内存碎片产生,而且大量的加载将会直接耗尽32位机的内存地址空间。2. 加载到主程序域的assembly将不会被卸载并释放内存,大量的加载会直接占用加载的内存 空间。应尽量减少加载小的Assmelby,并限制生成和加载新的Assmbly的次数。