zoukankan      html  css  js  c++  java
  • 第十一章 管理类型(In .net4.5) 之 管理对象的生命周期

    1. 概述

      本章内容包括 管理非托管资源、使用IDisposable接口 以及 管理析构器和垃圾回收。

    2. 主要内容

      2.1 理解垃圾回收机制

        ① 代码执行的时候,内存中有两个地方存放数据项:堆 和 栈。

        ② 一个方法结束的时候,其使用的栈空间会被自动清空。 而堆空间,是由垃圾回收器管理的。

        ③ 垃圾回收器的工作原理是:启动以后,垃圾回收器的标记程序会遍历堆上保存的对象,标记出仍然被引用的对象,然后压缩程序启动,它会把当前仍然存在引用的对象移动到一起,然后释放掉其他不存在引用的对象。

        ④ 执行垃圾回收期间,为了确保对象状态的准确性,系统会暂停其他所有线程的执行,直到垃圾回收执行完毕。这可能会导致一定的程序响应问题。

        ⑤ 为了解决上述问题,垃圾回收器被设计成智能的。它会尽量在堆空间不足或内存不足的时候启动,而且尽量会在程序使用率低的时候启动。

        ⑥ 执行标记程序的时候,首次遍历到的对象默认是Generation 0,如果检测到该对象存在引用,则会提高该对象的Generation。其中根据的原则是:长时间停留的对象,可能会停留较长时间。所以这些对象仅会在空间不足的时候才会去检测和释放。

      2.2 管理非托管资源

        不涉及非托管资源的时候,基本无需考虑内存及资源管理问题,垃圾回收器都能处理好。但是一旦涉及到非托管资源,垃圾回收器就无能为力了,这时候就需要手动释放资源。

        析构器(finalizer)是释放资源的一种方式,但是C#中,析构器的执行时间是不确定的,是由垃圾回收器的算法决定的。但是可以通过调用GC.Collect来强制执行析构器。(这种做法是不推荐的)

    StreamWriter sw = File.CreateFile("temp.dat");
    sw.Write("some data");
    GC.Collect();
    GC.WaitForPendingFinalizers();
    File.Delete("temp.dat");

       析构器延长了对象的生命周期。因为析构器总要执行,.net平台会在一个特殊的析构队列中保存一个该对象的引用。这会推迟垃圾回收器的回收时间。

        综上所述,对于释放非托管资源,析构器不是一个很好的方案。.net有更好的推荐:IDisposable。

    using(StreamWriter stream = File.CreateText(“temp.dat”))
    {   stream.Write(“some data”);   stream.Dispose();   File.Delete(“temp.dat”);
    }

        使用using,可以自动处理其中代码的异常情况,避免因为代码中的异常可能导致的资源没有释放的问题。

      2.3 实现IDisposable接口和析构器

        在自定义类型中同时实现IDisposable接口和析构器,是一个必要的方案。可以避免用户忘记调用Dispose方法的情况。

    class UnmanagedWrapper : IDisposable
    {
        public FileStream Stream { get; private set;}
    
        public UnmananagedWrapper()
        {
            this.Stream = File.Open("temp.dat", FileMode.Create);
        }
    
        ~UnmanagedWrapper()
        {
            Dispose(false);
        }
    
        public void Close()
        {
            Dispose();
        }
    
        public void Dispose()
        {
            Dispose(true);
            System.GC.SuppressFinalizer(this);
        }
    
        public void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (Stream != null)
                    Stream.Close();
            }
        }
    }        

        * System.GC.SuppressFinalizer(object obj)会请求系统不要调用指定对象的析构器。

      2.4 弱引用(weak references)

    static WeakReference data;
    public  static void Run()
    {
        object result = GetData();
        //GC.Collect(); 取消这行注释将会导致data.Target为null
        result = getData();
    } 
    private static object GetData()
    {
        if (data == null)
            data = new WeakReference(LoadLargeList());
    
        if (data.Target == null)
            data.Target = LoadLargeList();
    
        return data.Garget;
    }

       弱引用可用于缓存场景,用弱引用定义的对象,不会阻碍垃圾回收器的回收。上面的GetData方法,确保在对象被回收以后,重新获取并保存对象。

    3. 总结

      ① C#中,用堆和栈在内存中保存数据项。堆空间是受垃圾回收器管理的。

      ② 垃圾回收器会释放堆上那些已经不存在引用的对象。

      ③ 析构器是类中一段特殊的代码,在类对象被删除的时候,由垃圾回收器负责调用。

      ④ IDisposable接口,可以实现用可控的方式来释放非托管资源。

      ⑤ 可以用using关键字来确保实现了IDisposable的对象总会被成功释放。

      ⑥ 弱引用 可以保存一个对象,该对象会被垃圾回收器当做已经没有引用的对象而回收。

  • 相关阅读:
    隐藏导航练习
    分层导航
    做一个问题,如果输入的答案正确则弹出正确,错误弹出错误
    同意按钮,倒计时10秒
    golang strings
    seek指针大文件上传
    go文件操作大全
    zipimport.ZipImportError: can't decompress data; zlib not available 解决办法
    centos 安装redis自启动要点
    golang 文件读取
  • 原文地址:https://www.cnblogs.com/stone_lv/p/4369539.html
Copyright © 2011-2022 走看看