zoukankan      html  css  js  c++  java
  • 不是GC打酱油,是人打酱油

     

    不是GC打酱油,是人打酱油

    之前在一个技术群里看到有人讨论内存释放问题,引发对GC的讨论,大体结论是GC不可靠,GC是打酱油的。

    之所以得出这个结论,是因为我们大多时候使用的是GC.Collect(),同时并未提供大内存对象的析构函数并在析构函数中释放内存。

    如有类:

    public class BufWrapper

    {

        private byte[] buf;

        public BufWrapper()

        {

            buf=new byte[1024*1024*2];

        }

        ~BufWrapper()

        {

            buf=null;

        }

    }

    对此写测试代码:

    BufWrapper br=null;

    while(true)

    {

        br=null;

        br=new BufWrapper();

    }

    这样的代码必定导致内存问题,原因在于虽然每次循环将上次创建的br设置为null使其引用数得以置零,但 .net的垃圾回收机制在默认情况下并不立即执行其析构函数,从而此对象中的buf不能被立即释放。所以,考虑为测试代码增加GC.Collect():

    BufWrapper br=null;

    while(true)

    {

        br=null;

        br=new BufWrapper();

        GC.Collect();

    }

    测试会发现,内存有所控制,但长时间观察,仍然呈波动上升趋势,而这应该正是大家怀疑GC的原因所在。其实,GC.Collect()也并不保证垃圾对象被立即回收。所以,一般建议为对象实现IDisposable接口,通过代码主动释放:

    public class BufWrapper:IDisposable

    {

        private byte[] buf;

        public BufWrapper()

        {

            buf=new byte[1024*1024*2];

        }

        ~BufWrapper()

        {

            this.Dispose();

        }

        public virtual void Dispose()

        {

            buf=null;

        }

    }

    测试代码:

    BufWrapper br=null;

    while(true)

    {

        if(br!=null)br.Dispose();

        br=new BufWrapper();

    }

    测试发现,以上代码不存在内存问题。

    但是,这里就存在一个问题,如果现有对象并未实现IDisposable接口,或实现的接口方法中并未释放资源怎么办?GC.Collect()不能保证立即释放资源,怎么办?

    其实GC还有一个方法:GC.WaitForPendingFinalizers()。使用以下代码(甚至BufWrapper不提供析构函数):

    public class BufWrapper

    {

        private byte[] buf;

        public BufWrapper()

        {

            buf=new byte[1024*1024*2];

        }

    }

    测试代码:

    BufWrapper br=null;

    while(true)

    {

        br=null;

        br=new BufWrapper();

        GC.Collect();

        GC.WaitForPendingFinalizers();

    }

    曾经怀疑GC的人,会惊奇的发现,以上代码也不存在内存问题。

    这个方案在不改动现有类(未实现释放资源的IDisposable接口)的情况下,解决了内存问题,但它也存在一些的问题,如果有机会,在以后再和大家详细讨论。

    注:对于技术问题,我喜欢提供详细方案,但不愿意对细节做太多解释,只希望有需要的人能以此为基础自行比较研究,从而获取更多

    十年磨一剑,五年磨一半
  • 相关阅读:
    DBCP数据库连接池
    Java Ant build.xml详解
    AWK 用法
    java打jar包
    linux 下java jar包的方法
    linux下java命令行引用jar包
    java webservice
    设计模式的几大原则
    ContextLoaderListener
    WebApplicationContextUtils源码
  • 原文地址:https://www.cnblogs.com/encounter/p/2188900.html
Copyright © 2011-2022 走看看