NET垃圾回收机制

http://www.shehui001.com/map.asp?pid=306

 http://social.microsoft.com/Forums/zh-CN/visualcshartzhchs/thread/6591f09d-4f74-40fa-9243-1373f1be273d

  

一下回复节选自《程序员面试指南》,你可以检查一下这些方面的问题,你的问题很可能是不断地创建新对象,而垃圾回收器来不及回收导致的,你看看是否有在循环中不断创建新对象的情况:

在一些不规范的编码情况下,即使是拥有垃圾回收和内存管理机制的托管堆上,仍然可能出现内存泄漏。首先读者需要了解什么是内存泄漏。
    内存泄漏是指内存空间上产生了不再被实际使用却又不能被分配的内存,内存泄漏的意义很广泛,例如程序无意义地保持对象内存、内存碎片、不彻底的对象释放等 都属于内存泄漏现象。内存泄漏将导致主机的内存随程序的运行而逐渐减少,无论内存泄漏的具体形式如何,它的危害都是显而易见的,所有的内存泄漏都是需要程 序员努力避免的。
按照内存泄漏的定义,大部分时候.NET的托管堆中存在着短暂的内存泄漏情况,那是因为对象一旦不被使用后,需要等到下一个GC 时才能被释放。这里,笔者将举出其他几种对系统危害更大的内存泄漏情况:
1)大对象的分配
.NET中所有的大对象将分配在托管堆内一个特 殊的区域,这里暂时称呼它为“大对象堆”。在回收大对象堆内的对象时,其他的大对象不会被移动,这是考虑到大规模地移动对象需要耗费过多的资源。这样,在 程序过多地分配和释放大对象之后,就会产生很多内存碎片。
,随着对象的分配和释放不断进行,在不进行对象移动的大对象堆内,将不可避免地产生小的 内存碎片。程序员对此能做的就是尽量减少大对象的分配次数,尤其是那些作为局部变量的,将被大规模分配和释放的大对象,典型的例子就是String类型, 关于String的使用在后续章节将有详细的叙述。
2)不恰当地保存根引用
最简单也最常见的错误做法可能就是不恰当地把一个对象申明为公 共静态变量,一个公共的静态变量将一直被GC视为一个在使用的根引用,而更糟糕的情况是,当这个对象内部还包含更多的对象引用时,这些对象同样不会被释 放。看一段简单的代码:代码3-19。
代码3-19  保存根引用:RefRoot.cs
namespace NET.MST.Third.RootRef
{
    public class RefRoot
    {
        //这里是一个占用大量内存的成员
        public String[] BigMembor;
        public RefRoot(String content)
        {
            //初始化大对象
            BigMembor = new String[1000];
            for (int i = 0; i < BigMembor.Length; i++)
                BigMembor[i] = content;
        }
    }
    public class MainClass
    {
       //公共静态大对象
        public static RefRoot bigobject = new RefRoot("aaa");
        static void Main()
        {
            Console.Read();
        }
    }
}
在代码3-19中,MainClass定义了一个公共静态的大对象,这个对象将直至程序运行结束后才会被GC释放。这一段代码的设 计是否成功将取决于这个公共静态变量被使用的频率以及业务逻辑,如果在整个程序中各个类型不断地使用这个静态成员,那这样的设计有助于减少大对象堆内的内 存碎片,但如果整个程序极少地甚至于只有一次使用了这个成员,那考虑到它占用的内存会影响整体系统的性能,设计时应该考虑把他设计成实例变量,以便于GC 能够及时地释放它。
这里仍然只从性能的角度考虑问题,实际的设计情况不仅需要考虑性能,还需要考虑程序的和架构和可扩展性。
3)3)不正 确的Finalize方法
在前述章节中笔者已经介绍了,Finalize方法由一个专用的线程进行调用,微软并没有公开这部分具体的调度算法,但 是有一点却是肯定的,不正确的Finalize方法将导致Finalize方法不能被正确执行,系统中所有的Finalize方法不能被正确执行时,包含 它们的对象也只能驻留在托管堆内不能被释放,这样的情况将会导致严重的后果。
Finalize方法应该只致力于快速而简单地释放非托管资源,并且 尽可能快地返回。不正确的Finalize方法可能包含这样的代码:
?    没有保护地写文件日志
?    访问数据库
?    访问网络
?    把当前对象赋给某个存活的引用
当Finaize方法访问文件系统、数据库系统或者网络时,将会有资源争用和等待的 潜在危险。试想一个试图不断尝试访问离线数据库的Finalize方法,将会在长时间内不会返回,这不仅影响了本身对象的释放,也使得排在 Finalize方法队列中的所有后续对象得不到释放,这个连锁反应将很快造成内存耗尽。

而另外一种危险的代码是在Finalize方法中把对象 自身又赋给了另外一个存活的引用,这时对象内的一部分资源已经被释放了,而另外一部分则没有,这样一个对象被再次激活后,将导致不可预知的后果。 

转载于:https://www.cnblogs.com/BpLoveGcy/archive/2010/05/23/1741939.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值