1.内存分配
a.栈分配
b.对分配
2.合理使用内存
.内存分配
系统新建一个线程的时候为这个线程分配一个1M(XP系统)大小的空间,栈采用先入后出的原则存储着数据和指令,当执行完毕后,栈内应该为空,.net 代码在被编译成IL二进制后,IL就是一系列指令和元数据说明等,这些指令就包含了栈的调用,对象的实例化等等,所以栈的空间回收是系统完成的。
.net 中对象分配在堆中,并且由GC来回收不用的对象所占的空间。对Heap包含GCHeap和LoaderHeap,GCHeap表示的是能有GC回收的堆区域(堆栈都是逻辑上的),GCHeap包含小对象堆和大对象堆(Large object Heap>=85000字节).LoaderHeaper包含High-Frequency Heap、Low-Frequecy Heap、Stub Heap。
GCHeap 小对象堆与大对象堆最大的不同时GC在回收空间的时候,会对小对象堆中的有效对象进行移动,使他们放在一起,对Loh不会移动空间。
对小对象堆得回收过程是:GC首先认为所有的对象都是可以被回收的,然后通过算法计算哪些对象现在是有效地(在栈上去找存不存在这些空间的引用),把有效地对象给标记出来,然后回收不小对象的空间,进而就把这些有效对象移动到一起(这个过程中会计算对象的代数,最多三代,所以是“第三代对象|第二代对象|第一代对象”),在回收的时候会优先回收第一代对象),同时更新对象在栈中存储的引用地址为新地址,这样就有很多的内存空间并且是一次分配的(分配的时候有一个指向最后分配位置的指针,这样在分配新的对象的时候十分快速,当分配到最后堆空间不够分配的时候,CLR会启动GC回收,所以一般不提倡人为调用GC去回收内存,可能会扰乱CLR的正常工作)。
对LOH,分配内存的时候会挨着随后一个分配,如果遇到不能分配的时候,启动GC ,Gc 回收空间,回收后不会移动对象地址(一定空间本身就是一个不小的消耗),后分配的对象会找一个能放下自己的空间。这样降低了内存利用。这是一个综合的考虑结果(鱼与熊掌不可兼得),“85000字节”也是一个经验值。
内存条,内存条就是一个电路板,其中有很多的电路元件,晶体是其中的重要组成部分,用过电位(通断,有无电压)来表示0或者1,通过一个总线对外表示表示内存大小和内存地址,定位,通过改变晶体导电性,来达到记录(写)的目的。
相应连接地址:
1..NET内存管理、垃圾回收 http://www.cnblogs.com/riccc/archive/2009/09/01/dotnet-memory-management-and-garbage-collection.html
2.你必须知道的.NET——内存分配 http://www.cnblogs.com/cheshui/archive/2012/09/29/2707910.html
3.windows编程内存篇-实验讲解线程栈 http://hi.baidu.com/wesley0312/item/a3e02e9b7d36a48e59146124
.net 在代码中的 对象回收和 内存利用
1.正确的书写代码
明确Finalize,Dispose,Close。
代码中经常会开到对非托管对象的引用比如:Com组件,文件读写,数据库访问等等。
GC回收对象的时候,如果该对象含有对非托管对象的引用,那么就回提示异常,GC不能结束掉对非托管对象的引用,需要我们手动来实现,为了保证GC回收对象的时候能结束掉对非托管引用对象,所以又了Finalize方法(析构函数编译后就编译成的Finalize方法)。Finalize,代码中不能显示重写Finalize方法(override方式),通过析构函数结束对非托管对象的引用
因为GC会在一些情况下启动并回收对象,回收对象的的时间又可能不是我们想要的(比如:数据访问,假如我们也写了finalize方法,但是GC执行延迟,当我们第二次调用数据库连接对象的时候,GC还没有对该对象回收,并且长久的连接也消耗了资源),这时候我们需要另外一种方法,那就是IDisposable接口,这个接口.Net 类库中有定义,实现其中的Dispose方法,提供显示地结束掉对非托管代码的引用(不同的非托管资源结束引用方式可能不同,比如文件读取调用Closehandle方法(系统方法))。为了更好的的书写代码c#中有Using关键字,对象使用完后自动调用对象的Dispose方法,方便我们书写。
对于文件读写和数据连接这样珍贵的非托管资源(具有独占性),我们一般是在想用的时候主动的打开引用,不用的时候就结束掉,有一个成对的“开-关”关系,所以习惯山我们会有一个Open和Close方法。
所以,我们在写关于非托管的引用的时候,就最好把Finalize,Dispose,Close方法都合理的运用上。
2.合理使用大对象
大对象占用不少空间,有不利于GC的回收,怎么办呢?
其一:使用小对象,把对象转换成小对象(比如:把大字符串使用过个小字符串来存储);
其二:对对象弱引用:(WeakReference类):这个类的原理,比如 WeakReference wr = new WeakReference(A); A是一个大对象,占用不少空间,当使用弱引用后,当GC回收空间的时候即使在我们程序中没又被标记无效(A= null),A还是会被回收,从而节约了空间。后期再想使用怎么办了?先判断一下wr.Target是否为null,如果为null则表示被回收掉了,需要重新创建分配A,如果不为null,则表示还没有被GC回收掉,可以继续使用。这也是一个妥协的做法。
相应连接地址:
NET陷阱之五:奇怪的OutOfMemoryException——大对象堆引起的问题与对策 http://www.cnblogs.com/brucebi/archive/2013/04/16/3024136.html
System.OutOfMemoryException: http://www.cnblogs.com/emanlee/archive/2009/06/25/1511198.html
WeakReference 类http://msdn.microsoft.com/zh-cn/library/vstudio/system.weakreference.aspx