• C#GC垃圾回收和析构函数和IDisposable的使用


    一,什么是GC

    1,GC是垃圾回收器,一般来说系统会自动检测不会使用的对象或变量进行内存的释放,不需要手动调用,用Collect()就是强制进行垃圾回收,使内存得到及时的释放,让程序效率更高.

    2,GC:只负责回收托管对象,不负责回收非托管对象。

    那什么是垃圾? 垃圾是完全访问不到的东西了,就是当前程序执行后该对象或值没有被引用

    如下图:

    代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace TestDemo
    {
        public class TestDemo
        {
            private static Test t = new Test()//静态的不可能被回收   静态持有的引用也不会被回收
            {
                Id = 123,
                Name = "Test"
            };
            public static void show()
            {
                ///{}这个括号是代码分块的意思,两个块之间是不影响的,第一块执行完后,一般来说就是会被主动GC释放
                ///而这里obj没有被释放的原因是因为静态遍历对obj这个引用类型变量的使用
                {
                    object obj= new { Name = 1 };
                    t.obj = obj;
                    int i = 3;//都会被GC
                    TestDemo testDemo = new TestDemo();//都会被GC
                }
                {
                    GC.Collect();//主动GC
                }
            }
        }
    
        public class Test
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public object obj { get; set; }
        }
    }

    总结:程序执行完会回收垃圾,这个obj还在静态的t使用,所以没有被释放

    那GC怎么回收呢?
    1,new的时候发现内存不够 就去遍历所有堆的对象,标记访问不到,然后启动一个线程来清理内存
    2,清除标记了的对象,其他挪动,然后整齐摆放,所以这个时候全部线程停止,不允许操作内存
    3,内存不够的是指一级对象的内存,有个临界值,也不是全部的堆的大小

    GC回收执行的过程:
    1, 首次GC前 全部对象都是0级
    2, 第一次GC后,还保留的对象叫1级
    3, 回收先找0级对象,如果空间还不够,再去找1级对象,这之后,还存在的对象就变成2级
    4, 0级不够,1级也不够,2级还不够,那就内存溢出了
    5,越是最近分配的,越是会被回收 比如for循环创建对象

    大对象和正常的对象缓存的地址是不一样的。
    大对象策略:如果大于某个值的对象85k,单独管理,用的是链表(碎片),避免频繁的内存移动

    二,析构函数和IDisposable的区别?

    ~Class() 析构函数: 主要是用来释放非托管资源,等着GC的时候去把非托管资源释放掉 系统自动执行
    GC回收的时候,CLR一定调用的,但是可能有延迟(释放对象不知道要多久呢)

    Dispose() :也是释放非托管资源的,主动释放,方法本身是没有意义的,我们需要在方法里面实现对资源的释放
    GC不会调用,而是用对象时,使用者主动调用这个方法,去释放非托管资源,
    而不是说对象释放的时候,会去自动调用Dispose方法,然后在用完对象时,我们主动去执行dispose方法,当然可以是using的快捷方式

    如下代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace TestDemo
    {
        public class TestDemoThree
        {
            public static void show()
            {
                {
                    for (int i = 0; i < 2; i++)
                    {
                        TestThree @class = new TestThree()
                        {
                            Id = i,
                            Name = "TestThree"
                        };
                    }
                }
                {
                    GC.Collect(); //主动GC的时候,CLR一定调用的析构函数
                }
                {
                    ///using 这个会去调用调用的dispose,相当于try后的finally
                    using (TestThree TestThree = new TestThree()
                    {
                        Id = 1,
                        Name = "444"
                    })
    
                        try
                        {
                            //using相当于
                        }
                        finally
                        {
                            //调用的dispose()
                        }
                }
            }
    
            public class TestThree : IDisposable
            {
                public int Id { get; set; }
                public string Name { get; set; }
                ~TestThree()
                {
                    Console.WriteLine($"执行{this.GetType().Name}~TestThreeDispose");
                }
                public void Dispose()
                {
                    Console.WriteLine($"执行{this.GetType().Name}Dispose");
                }
            }
        }
    }

    主动执行GC执行结果

     using执行结果

  • 相关阅读:
    CentOS配置启动ssh与开机自启
    CentOS中怎样安装、配置、启动Nginx
    CentOS中配置Mysql表名忽略大小写以及提示:Caused by: org.quartz.impl.jdbcjobstore.LockException: Failure obtaining db row lock的解决
    CentOS中部署jar包时提示:org.quartz.SchedulerException: Couldn't get host name
    CentOS6中怎样将jdk1.7升级到1.8
    CentOS6在使用yum install 时提示镜像源路径不存在:PYCURL ERROR 22
    信息系统项目管理师-项目立项管理考点笔记
    chrome89不再支持/deep/的解决方案
    手写async await
    proxy和reflect
  • 原文地址:https://www.cnblogs.com/May-day/p/11398776.html
Copyright © 2020-2023  润新知