zoukankan      html  css  js  c++  java
  • 对象的生命周期 笔记

    In fact, the golden rule of .NET memory management is simple:

    Rule Allocate an object onto the managed heap using the new keyword and forget about it.

    事实上,在.NET中我们进行内存管理的法则非常简单.

    l  法则1: 使用new关键字将一个对象分配在托管堆上(对象的引用在栈上),然后就不用再管。

    Rule If the managed heap does not have sufficient memory to allocate a requested object, a garbage collection will occur.

    l  法则2:  如果托管堆没有足够的内存来分配所请求的对象,就会进行垃圾回收。

    What you must understand, however, is that assigning a reference to null does not in any way force the garbage collector to fire up at that exact moment and remove the object from the heap. The only thing you have accomplished is explicitly clipping the connection between the reference and the object it previously pointed to.

    不管怎样,我们必须知道,将引用赋值为null并不意味着强制垃圾回收器立即启动并把对象从堆上移除。我们完成的唯一事情就是显式取消引用和之前引用所指向的对象之间的连接。

    Understanding Object Generations

    To help optimize the process, each object on the heap is assigned to a specific “generation.” The idea behind generations is simple: the longer an object has existed on the heap, the more likely it is to stay there.

    对象的代

    垃圾回收为了效率的考虑,给每一个堆上的对象一个标记“代”。对象在堆上存在的时间越长,它就更可能应该保留。

    • Generation 0: Identifies a newly allocated object that has never been marked for collection

    • Generation 1: Identifies an object that has survived a garbage collection (i.e., it was marked

    for collection, but was not removed due to the fact that the sufficient heap space was

    acquired)

    • Generation 2: Identifies an object that has survived more than one sweep of the garbage

    Collector

    • 第0代:从没有被标记为回收的新分配对象。
    • 第1代:在上一次垃圾回收中没有被回收的对象。(也就是上一次标记后,因为已经获取了足够的堆空间或者还不能回收它而没有被删除。并不是标记了就会被回收,每个对象都有标记。)
    • 第2代:在上一次垃圾回收后仍然没有被回收的对象。

    The garbage collector will investigate all generation 0 objects first. If marking and sweeping these objects results in the required amount of free memory, any surviving objects are promoted to generation 1.

    垃圾回收器首先要调查所有的第0代对象。如果标记和清除这些对象得到了所需数量的空闲内存,任何没有被回收的对象都被提升到第1代。

    If all generation 0 objects have been evaluated, but additional memory is still required, generation 1 objects are then investigated for their “reachability” and collected accordingly. Surviving generation 1 objects are then promoted to generation 2.

    如果算上所有的第0代对象后仍然需要更多的内存,就会检查第1代对象的“可达性”并相应地进行回收。没有被回收的第1代对象随后被提升到第2代。

    第2代的回收同理。只是没被回收的第2代不会升为第3代,因为没有第3代。

    The bottom line is that by assigning a generational value to objects on the heap, newer objects (such as local variables) will be removed quickly, while older objects (such as a program’s application object) are not “bothered” as often.

    这里的要点是,通过给堆上的对象赋一个表示代的值,尽快地删除一些较新的对象(如本地变量),而不会经常打扰到一些旧的对象(例如程序的应用程序对象)。

    The System.GC Type

    Now, do be very aware that you will seldom (if ever) need to make use of this type directly in your code. Typically speaking, the only time you will make use of the members of System.GC is when you are creating types that make use of unmanaged resources.

    System.GC类型

    这里要特别注意的是,极少需要在代码中直接使用这个类型。也就是说,只有在创建那些使用非托管资源的类型时,才需要使用System.GC的成员。

    static void Main(string[] args)
    {
        Console.WriteLine("***** Fun with System.GC *****");
        // Print out estimated number of bytes on heap.
        Console.WriteLine("Estimated bytes on heap: {0}",
        GC.GetTotalMemory(false));
        // MaxGeneration is zero based, so add 1 for display purposes.
        Console.WriteLine("This OS has {0} object generations.\n",
        (GC.MaxGeneration + 1));
        Car refToMyCar = new Car("Zippy", 100);
        Console.WriteLine(refToMyCar.ToString());
        // Print out generation of refToMyCar object.
        Console.WriteLine("Generation of refToMyCar is: {0}",
        GC.GetGeneration(refToMyCar));
        Console.ReadLine();
    }
    static void Main(string[] args)
    {
        Console.WriteLine("***** Fun with System.GC *****");
        // 输出堆上的估计的字节数。
        Console.WriteLine("Estimated bytes on heap: {0}",
        GC.GetTotalMemory(false));
        // MaxGeneration是从0开始的,因此为了显示的目的加上了1.
        Console.WriteLine("This OS has {0} object generations.\n",
        (GC.MaxGeneration + 1));
        Car refToMyCar = new Car("Zippy", 100);
        Console.WriteLine(refToMyCar.ToString());
        // 输出refToMyCar对象的迭代.
        Console.WriteLine("Generation of refToMyCar is: {0}",
        GC.GetGeneration(refToMyCar));
        Console.ReadLine();
    }


    Forcing a Garbage Collection

    Under some very rare circumstances, it may be beneficial to programmatically force a garbage collection using GC.Collect(). Specifically:

    • Your application is about to enter into a block of code that you do not wish to be interrupted by a possible garbage collection.

    • Your application has just finished allocating an extremely large number of objects and you wish to remove as much of the acquired memory as possible.

    static void Main(string[] args)
    {
        ...
        // Force a garbage collection and wait for
        // each object to be finalized.
        GC.Collect();
        GC.WaitForPendingFinalizers();
        ...
    }
    static void Main(string[] args)
    {
        ...
        // Only investigate generation 0 objects.
        GC.Collect(0);
        GC.WaitForPendingFinalizers();
        ...
    }

    强制垃圾回收

    在一些非常罕见的环境下,通过编程使用GC.Collect()强制进行可能会有好处。尤其是:

    • 应用程序将要进入一段代码,后者不希望被可能的垃圾回收中断;
    • 应用程序刚刚分配非常多的对象,你想尽可能多地删除已获得的内存。
    static void Main(string[] args)
    {
        ...
        //强制一次垃圾回收,并等待每一个对象都被终结。
        GC.Collect();
        GC.WaitForPendingFinalizers();
        ...
    }
    static void Main(string[] args)
    {
        ...
        // 只检查第0代对象。
        GC.Collect(0);
        GC.WaitForPendingFinalizers();
        ...
    }


    Be very aware that the following techniques will only be useful if you are building managed classes that maintain internal unmanaged resources.

    下面的技术仅在创建需要维护内部非托管资源的托管类时有用。

    Building Finalizable Objects

    The supreme base class of .NET, System.Object, defines a virtual method named Finalize(). The default implementation of this method does nothing whatsoever:

    // System.Object
    public class Object
    {
        ...
        protected virtual void Finalize() {}
    }

    When you override Finalize() for your custom classes, you establish a specific location to perform any necessary cleanup logic for your type. Given that this member is defined as protected, it is not possible to directly call an object’s Finalize()method from a class instance via the dot operator. Rather, the garbage collector will call an object’s Finalize()method (if supported) before removing the object from memory.

    构建可终结对象

    .NET的基类System.Object,定义了名为Finalize()的虚方法。这个方法的默认实现是什么都不做的:

    // System.Object
    public class Object
    {
        ...
        protected virtual void Finalize() {}
    }

    当为自定义的类重写Finalize()时,就建立了一个地方,来为类型执行必要的清理逻辑。因为这个成员是protected的,所以不可能通过点操作符来直接调用。在从内存删除这个对象之前,垃圾回收器会调用它。

    Note It is illegal to override Finalize() on structure types. This makes perfect sense given that structures are value types, which are never allocated on the heap to begin with, and therefore are not garbage collected!

    说明  在结构中重写Finalize()是不合法的。因为结构是值类型,他们本来就从不分配在堆上,也就不能被回收。

    Rule The only reason to override Finalize() is if your C# class is making use of unmanaged resources via PInvoke or complex COM interoperability tasks (typically via various members defined by the System.Runtime.InteropServices.Marshal type).

    • 法则3:  重写Finalize()的唯一原因是,C#类通过PInvoke或复杂的COM互操作性任务使用了非托管资源(典型情况是通过System.Runtime.InteropServices.Marshal类型定义的各成员)。

    The bottom line is that while finalization of an object does ensure an object can clean up

    unmanaged resources, it is still nondeterministic in nature, and due to the extra behind-the-

    curtains processing, considerably slower.

    总而言之,尽管对象的终结能够保证对象可以清除非托管的资源,但它本质上仍然是非确定的,而且由于额外的幕后处理,速度会变得相当慢。

    Building Disposable Objects

    When you do support the IDisposable interface, the assumption is that when the object user is finished using the object, it manually calls Dispose() before allowing the object reference to drop out of scope. In this way, an object can performany necessary cleanup of unmanaged resources without incurring the hit of being placed on the finalization queue and without waiting for the garbage collector to trigger the class’s finalization logic.

    构建可处置对象

    如果提供IDisposable接口,就是假设当对象的用户不再使用这个对象时,会在这个对象引用离开作用域之前手工地调用Dispose()。这样,对象可以执行任何必要的非托管资源的清除,而且不会再有(Finalize())将对象放在终结队列上导致的性能损失,也不必等待垃圾回收器触发类的终结逻辑。

    Note Structures and class types can both implement IDisposable (unlike overriding Finalize(), which is reserved for class types), as the object user (not the garbage collector) invokes the Dispose() method.

    说明  结构和类类型都可以实现IDisposable(与重写Finalize()不同,后者只适用于类类型),因为对象用户(不是垃圾回收器)会调用Dispose()方法。

    Rule Always call Dispose() on any object you directly create if the object supports IDisposable. The assumption you should make is that if the class designer chose to support the Dispose() method, the type has some cleanup to perform.

    • 法则4:  如果对象支持IDisposable,总是要对任何直接创建的对象调用Dispose()。应该认为,如果类设计者选择支持Dispose()方法,这个类型就需要执行清除工作。

    There is one caveat to the previous rule. A number of types in the base class libraries that do implement the IDisposable interface provide a (somewhat confusing) alias to the Dispose() method, in an attempt to make the disposal-centric method sound more natural for the defining

    type. By way of an example, while the System.IO.FileStream class implements IDisposable (and

    therefore supports a Dispose()method), it also defines a Close()method that is used for the same

    purpose:

    // Assume you have imported
    // the System.IO namespace...
    static void DisposeFileStream()
    {
        FileStream fs = new FileStream("myFile.txt", FileMode.OpenOrCreate);
        // Confusing, to say the least!
        // These method calls do the same thing!
        fs.Close();
        fs.Dispose();
    }

    For the few types that do provide an alias, just remember that if a type implements IDisposable, calling Dispose() is always a correct course of action.

    对于之前的规则还有一个补充:基类库中的许多类型都实现了IDisposable接口,并且还提供了Dispose()方法的一个别名(有点混淆),这样使得定义类型的释放相关的方法听上去更自然。例如,System.IO.FileStream类实现了IDisposable接口(因此也支持Dispose()方法),它还定义了用于相同目的的Close()方法:

    // 假设我们已经导入了System.IO命名空间...
    static void DisposeFileStream()
    {
        FileStream fs = new FileStream("myFile.txt", FileMode.OpenOrCreate);
        // 确实有点混淆,这两个方法调用完成相同的事情!
        fs.Close();
        fs.Dispose();
    }

    由于提供别名的类型也不是很多,我们只要记住,如果类型实现了IDisposable,调用Dispose()总是正确的。

    Reusing the C# using Keyword

    When you are handling a managed object that implements IDisposable, it will be quite common to make use of structured exception handling to ensure the type’s Dispose()method is called in the event of a runtime exception:

    static void Main(string[] args)
    {
        Console.WriteLine("***** Fun with Dispose *****\n");
        MyResourceWrapper rw = new MyResourceWrapper ();
        try
        {
            // Use the members of rw.
        }
        finally
        {
            // Always call Dispose(), error or not.
            rw.Dispose();
        }
    }

    To achieve the same result in a much less obtrusive manner, C# supports a special bit of syntax that looks like this:

    static void Main(string[] args)
    {
        Console.WriteLine("***** Fun with Dispose *****\n");
        // Dispose() is called automatically when the
        // using scope exits.
        using(MyResourceWrapper rw = new MyResourceWrapper())
        {
            // Use rw object.
        }
    }

    using关键字的新用法

    处理实现了IDisposable的托管对象时,经常需要使用异常处理来保证类型的Dispose()方法在出现运行时异常时调用:

    static void Main(string[] args)
    {
        Console.WriteLine("***** Fun with Dispose *****\n");
        MyResourceWrapper rw = new MyResourceWrapper ();
        try
        {
            // 使用rw的成员.
        }
        finally
        {
            // 无论是否发生错误,总是调用Dispose().
            rw.Dispose();
        }
    }

    为了用更令人接受的方式达到同样的结构,C#提供了一个如下的特殊语法:

    static void Main(string[] args)
    {
        Console.WriteLine("***** Fun with Dispose *****\n");
        // 当退出using作用域时,自动调用Dispose().
        using(MyResourceWrapper rw = new MyResourceWrapper())
        {
            // 使用 rw 对象.
        }
    }


    Note If you attempt to “use” an object that does not implement IDisposable, you will receive a compiler error.

    说明  如果试图“using”一个没有实现IDisposable的对象,将会收到编译器错误。

    Be aware that it is possible to declare multiple objects of the same type within a using scope. As you would expect, the compiler will inject code to call Dispose() on each declared object:

    static void Main(string[] args)
    {
        Console.WriteLine("***** Fun with Dispose *****\n");
        // Use a comma-delimited list to declare multiple objects to dispose.
        using(MyResourceWrapper rw = new MyResourceWrapper(),
        rw2 = new MyResourceWrapper())
        {
            // Use rw and rw2 objects.
        }
    }

    还要知道可以在using作用域中声明相同类型的多个对象。编译器会插入代码来调用每一个声明对象的Dispose()。

    static void Main(string[] args)
    {
        Console.WriteLine("***** Fun with Dispose *****\n");
        // 使用逗号分隔符来声明多个要释放的对象.
        using(MyResourceWrapper rw = new MyResourceWrapper(),
        rw2 = new MyResourceWrapper())
        {
            // 使用rw和rw2对象.
        }
    }

    Building Finalizable and Disposable Types

    If the object user does remember to call Dispose(), you can inform the garbage collector to bypass the finalization process by calling GC.SuppressFinalize(). If the object user forgets to call Dispose(), the object will eventually be finalized and have a chance to free up the internal resources.

    // A sophisticated resource wrapper.
    public class MyResourceWrapper : IDisposable
    {
        // The garbage collector will call this method if the
        // object user forgets to call Dispose().
        ~ MyResourceWrapper()
        {
            // Clean up any internal unmanaged resources.
            // Do **not** call Dispose() on any managed objects.
        }
        // The object user will call this method to clean up
        // resources ASAP.
        public void Dispose()
        {
            // Clean up unmanaged resources here.
            // Call Dispose() on other contained disposable objects.
            // No need to finalize if user called Dispose(),
            // so suppress finalization.
            GC.SuppressFinalize(this);
        }
    }

    构建可终结类型和可处置类型

    如果对象用户记住了调用Dispose(),可以通过调用GC.SuppressFinalize()通知垃圾回收器跳过终结过程;如果对象用户忘记了调用Dispose(),对象最终也将被终结并有机会释放内部资源。

    // 高级的资源包装器.
    public class MyResourceWrapper : IDisposable
    {
        // 如果对象用户忘记调用Dispose(),垃圾回收器会调用这个方法.这个方法其实就是Finalize()。C#中比较奇怪的就是不能用override重写Finalize(),只能用下面的方式。。
        ~ MyResourceWrapper()
        {
            // 清除所有内部的非托管资源.
            // 不要调用任何托管对象的Dispose().
        }
        // 对象用户将调用这个方法来尽快清除资源.
        public void Dispose()
        {
            // 在这里清除非托管资源.
            // 在其他包含的可处置对象上调用Dispose().
    
            // 如果用户调用了Dispose()就不需要终结,因此跳过终结.
            GC.SuppressFinalize(this);
        }
    }


    A Formalized Disposal Pattern

    Microsoft has defined a formal, prim-and-proper disposal pattern that strikes a balance between robustness, maintainability, and performance.

    public class MyResourceWrapper : IDisposable
    {
        // Used to determine if Dispose()
        // has already been called.
        private bool disposed = false;
        public void Dispose()
        {
            // Call our helper method.
            // Specifying "true" signifies that
            // the object user triggered the cleanup.
            CleanUp(true);
            // Now suppress finalization.
            GC.SuppressFinalize(this);
        }
        private void CleanUp(bool disposing)
        {
            // Be sure we have not already been disposed!
            if (!this.disposed)
            {
                // If disposing equals true, dispose all
                // managed resources.
                if (disposing)
                {
                    // Dispose managed resources.
                }
                // Clean up unmanaged resources here.
            }
            disposed = true;
        }
        ~MyResourceWrapper()
        {
            // Call our helper method.
            // Specifying "false" signifies that
            // the GC triggered the cleanup.
            CleanUp(false);
        }
    }

    正式的处置模式

    微软定义了一个正式甚至有些刻板的处置模式,它在健壮性、可维护性和性能三者间取得了平衡。

    public class MyResourceWrapper : IDisposable
    {
        // 用来判断Dispose()是否已经被调用.
        private bool disposed = false;
        public void Dispose()
        {
            // 调用辅助方法.
            // 指定"true"表示对象用户触发了清理过程.
            CleanUp(true);
            // 现在跳过终结.
            GC.SuppressFinalize(this);
        }
        private void CleanUp(bool disposing)
        {
            // 保证我们还没有被处置!
            if (!this.disposed)
            {
                // 如果disposing等于true,释放所有托管的资源.
                if (disposing)
                {
                    // 释放托管的资源.
                }
                // 在这里清理非托管的资源.
            }
            disposed = true;
        }
        ~MyResourceWrapper()
        {
            // 调用辅助方法.
            // 指定"false"表示GC触发了清理过程.
            CleanUp(false);
        }
    }
  • 相关阅读:
    HTTP/2的优先级
    JavaScript 日期权威指南
    岂曰无衣与子同袍
    Android项目中实现native调用
    关键渲染路径
    @ModelAttribute使用详解
    @SessionAttribute使用详解
    @ControllerAdvice 拦截异常并统一处理
    js获取文件MD5值
    Mybatis分页插件PageHelper的配置和使用方法
  • 原文地址:https://www.cnblogs.com/tangzhengyue/p/2526741.html
Copyright © 2011-2022 走看看