美文网首页
C# GC与内存管理

C# GC与内存管理

作者: CodeVin | 来源:发表于2019-03-03 18:30 被阅读0次

    GC即Garbage Collection,垃圾回收的意思。C#的垃圾回收器Garbage Collector会跟踪并回收托管内存中分配的对象。垃圾回收器会周期性地执行垃圾回收,回收托管内存中没有被有效引用的对象。

    我们知道C#中的变量分为值类型和引用类型。值类型的变量存储在栈(stack)上,在作用域结束时自动释放,并不需要GC回收。引用类型的变量存储在堆(heap)上,在.NET 这种托管环境下,堆由CLR (公共语言运行库Common Language Runtime)进行管理,所以又称为“托管堆(managed heap)”。大部分对象都是托管资源,GC能够自动回收托管堆上的托管资源。但是GC不能自动回收非托管资源,常见的一般有操作系统资源对象,如:网络连接,文件流,数据库连接等。所以我们需要编写回收非托管资源的代码。

    释放非托管资源的正确方式,是为类型实现IDisposable接口的Dispose方法,当你需要释放类型的资源的时候,应该显式的调用Dipose方法。这里还有一个C#的语法糖,就是使用using程序块,在离开using程序块的时候,CLR会自动调用类型所创建对象的Dipose方法。如在Unity3D中使用WWW并释放网络连接资源的例子:

    public class ExampleClass : MonoBehaviour
    {
        public string url = "http://images.earthcam.com/ec_metros/ourcams/fridays.jpg";
        IEnumerator Start()
        {
            using (WWW www = new WWW(url))
            {
                yield return www;
                Renderer renderer = GetComponent<Renderer>();
                renderer.material.mainTexture = www.texture;
            }
        }
    }
    

    Dispose的实现示例如下:

    public class Foo : IDisposable
    {
        private bool disposed = false;
    
        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    //释放托管资源
                }
                // 释放非托管资源
                disposed = true;
            }
        }
    
        //既释放托管资源,又释放非托管资源
        public void Dispose()
        {
            Dispose(true);
            //将对象从垃圾回收器链表中移除,      
            //从而在垃圾回收器工作时,只回收托管资源,而不执行对象的析构函数
            GC.SuppressFinalize(this);
        }
        
        //以防开发人员忘记调用Dispose
        ~Foo()
        {
            Dispose(false);
        }
    }
    
    


    一些额外的Tips

    • String与StringBuilder

    String类型的变量是不可变的,当一个String类型的变量被初始化以后,任何对它的修改都会创建一个新的对象,当对一个字符串有频繁修改的需求时,会影响性能,而StringBuilder则没有这个问题。因此遇到上述情况用StringBuilder更合适。

    • Array,ArrayList和List

    数组Array

    优点:

    1. 数组在内存中是连续存储的,索引速度非常快
    2. 修改方便

    缺点:

    1. 声明时必须指定长度。长度过长内存浪费,长度不够造成溢出错误
    2. 插入数据麻烦

    针对于数组的这些缺点,C#中最先提供了ArrayList对象来克服这些缺点

    ArrayList

    ArrayList继承了IList接口

    优点:

    1. 无需指定长度,它的大小是按照其中存储的数据来动态扩充与收缩的
    2. 可以方便地进行数据添加与移除

    缺点:

    1. 类型不安全。ArrayList允许插入不同类型的数据,因为ArrayList会把所有插入其中的数据都当作为object类型来处理。
    2. 性能损耗问题。既使我们保证在插入数据的时候都很小心,都插入了同一类型的数据,但在使用的时候,我们也需要将它们转化为对应的原类型来处理。这就存在了装箱与拆箱的操作。

    装箱:就是将值类型的数据打包到引用类型的实例中
    拆箱:就是从引用数据中提取值类型
    装箱与拆箱的过程是很损耗性能的。

    泛型List

    正是因为ArrayList存在不安全类型与装箱拆箱的缺点,所以在C#2.0后出现了泛型的概念。而List类是ArrayList类的泛型等效类。它的大部分用法都与ArrayList相似,因为List类也继承了IList接口。最关键的区别在于,在声明List集合时,我们同时需要为其声明List集合内数据的对象类型。

    So, just use List.

    相关文章

      网友评论

          本文标题:C# GC与内存管理

          本文链接:https://www.haomeiwen.com/subject/egupuqtx.html