搜索

查看: 3092|回复: 11

[ASP.NET] ASP.NET堆和栈四之对托管和非托管资源的垃圾回收和内存分配

[复制链接]
发表于 2023-5-4 11:32:45 | 显示全部楼层 |阅读模式
Editor 2023-5-4 11:32:45 3092 11 看全部
".NET的堆和栈"系列:
ASP.NET堆和栈一之基本概念和值类型内存分配
ASP.NET堆和栈二之值类型和引用类型参数传递和内存分配
ASP.NET堆和栈三之引用类型对象拷贝和内存分配
ASP.NET堆和栈四之对托管和非托管资源垃圾的回收和内存分配
在" ASP.NET堆和栈一之基本概念和值类型内存分配"中,了解了"堆"和"栈"的基本概念,以及值类型的内存分配。我们知道:当执行一个方法的时候,值类型实例会在"栈"上分配内存,而引用类型实例会在"堆"上分配内存,当方法执行完毕,"栈"上的实例由操作系统自动释放,"堆"上的实例由.NET Framework的GC进行回收。
在" ASP.NET堆和栈二之值类型和引用类型参数传递和内存分配"中,我们了解了值类型参数和引用类型参数在传递时的内存分配情况。
在" ASP.NET堆和栈三之引用类型对象拷贝和内存分配"中,我们了解了在拷贝引用类型对象时的内存分配情况。
而本篇的重点要放在:对托管和非托管资源的垃圾回收、处理以及内存分配情况。
什么样的对象被GC认为是垃圾?
当托管堆中的对象不被任何其它对象所引用,这些对象将成为被释放的垃圾对象等待被GC回收。
每个应用程序都有一组根指针,这些根指针是不会被回收的,是由JIT编译器和CLR运行时维护的一个列表。主要包括:
  • 全局/静态指针:指向全局或局部静态变量
  • 栈指针:指向应用程序线程所需要的那部分栈上空间
  • 寄存器指针:指向托管堆所需要的那部分CPU中的内存地址

    2022813100936551.png

    2022813100936551.png


    以上,假设托管堆中有5个对象,1和5被跟指针引用,3依赖1,那么在这组托管堆对象中,2和4被回收后变成如下:

    2022813100936552.png

    2022813100936552.png


    当运行时有新的引用对象产生,将会被放到托管堆中这组对象的最上面。
    GC如何回收?
    GC对托管堆中对象的回收
    GC采用一定的算法在托管堆中遍历所有对象,最终形成一个可达对象和不可达对象,不可达对象将被回收。
    GC对非托管堆中对象的回收、处理
    对资源的回收
    比如文件、数据库链接、网络链接等,这些不再托管堆中的对象如何被回收呢?
    1、通过析构函数回收
    public class Sample
    {
        //析构函数
        ~Sample()
        {
        }
    }
    在托管堆中,那些带有析构函数的实例,将被放置到"Finalization Queue"中。

    2022813100936553.png

    2022813100936553.png


    对于那些不被任何其它对象所引用,如果没有析构函数,比如2,将被直接回收,如果有析构函数,例如4,会被放到"Freachable Queue"中,等待GC实施下一轮回收。

    2022813100936554.png

    2022813100936554.png


    当为一个类添加析构函数后,为GC增加了额外的工作,代价是比较昂贵的,更现实的做法是让类来实现IDisposable接口。
    2、通过实现IDisposable接口回收
    首先让一个类实现IDisposable接口。
    public class ResourceClass : IDisposable
    {
        public void Dispose()
        {
            //TODO:实现回收逻辑
        }
    }
    在应用程序中调用如下实施回收。
    using(ResourceClass re = new ResourceClass())
    {
       
    }
    对静态值类型变量的处理
    class Counter
    {
        private static int s_Number = 0;
         
        public static int GetNextNumber()
        {
            int newNumber = s_Number;
            
            // DO SOME STUFF
            
            newNumber += 1;
            s_Number = newNumber;
            return newNumber;
        }
    }
    如上,当方法有方法处理静态字段就需要注意了,2个线程同时调用GetNextNumber()会得到相同的结果,而我们的本意是:每调用一次方法,静态字段s_Number自增1。
    我们可以在处理逻辑块中加锁,每次只允许一个线程执行。
    class Counter
    {
        private static int s_Number = 0;
         
        public static int GetNextNumber()
        {
            lock (typeof(Counter))
            {
                int newNumber = s_Number;
                
                // DO SOME STUFF
                
                newNumber += 1;
                s_Number = newNumber;
                return newNumber;
            }
        }
    }
    对静态引用类型变量的处理
    class Olympics
    {
        public static Collection TryoutRunners;
    }

    class Runner
    {
        private string _fileName;
        private FileStream _fStream;

        public void GetStats()
        {
            FileInfo fInfo = new FileInfo(_fileName);
            _fStream = _fileName.OpenRead();
        }
    }
    以上,在GetStats()方法中,由于没有对FileStream及时关闭,如果Olympics恰巧有10万个Runner的集合,10万Runner都执行没有关闭FileStream的Gettats()方法,这将是一场灾难!
    Singleton模式可以很好地避免上述问题,它保证了在任何时候,内存中只存在某个类的一个实例。
    public class Earth
    {
        private static Earth _instance = new Earth();
        private Earth(){}
        public static Earth GetInstance(){return _instance;}
    }
    以上,单例模式的必要构成要素包括:
    1、私有静态引用类型变量
    2、私有构造函数
    3、获取类实例的静态方法
    GC何时回收?
    GC会周期性地执行垃圾回收、内存清理工作,以下情况会启动GC:
  • 托管堆内存不足溢出时
  • 调用GC.Collect()方法强制执行垃圾回收
  • Windows报告内存不足
  • CLR卸载AppDomain
    GC回收之后,又执行哪些操作?
    GC在垃圾回收之后,托管堆上将出现多个被收集对象的"空洞",为了避免托管堆的内存碎片,会重新分配内存、压缩托管堆。
    以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对知鸟论坛的支持。如果你想了解更多相关内容请查看下面相关链接
  • 回复

    使用道具 举报

    发表于 2023-6-29 12:48:56 | 显示全部楼层
    我是的十八簿 2023-6-29 12:48:56 看全部
    这东西我收了!谢谢楼主!知鸟论坛真好!
    回复

    使用道具 举报

    发表于 2023-6-29 15:03:28 | 显示全部楼层
    胡37 2023-6-29 15:03:28 看全部
    楼主太厉害了!楼主,I*老*虎*U!我觉得知鸟论坛真是个好地方!
    回复

    使用道具 举报

    发表于 2023-6-30 03:38:05 | 显示全部楼层
    墙和鸡蛋 2023-6-30 03:38:05 看全部
    这东西我收了!谢谢楼主!知鸟论坛真好!
    回复

    使用道具 举报

    发表于 2023-6-30 09:29:19 | 显示全部楼层
    ffycxyw2274436 2023-6-30 09:29:19 看全部
    论坛不能没有像楼主这样的人才啊!我会一直支持知鸟论坛
    回复

    使用道具 举报

    发表于 2023-6-30 18:45:27 | 显示全部楼层
    啤酒瓶空了缓 2023-6-30 18:45:27 看全部
    这个帖子不回对不起自己!我想我是一天也不能离开知鸟论坛
    回复

    使用道具 举报

    发表于 2023-7-3 11:17:10 | 显示全部楼层
    贰十岁装成熟装s 2023-7-3 11:17:10 看全部
    我看不错噢 谢谢楼主!知鸟论坛越来越好!
    回复

    使用道具 举报

    发表于 2023-7-3 12:29:38 | 显示全部楼层
    dxf17 2023-7-3 12:29:38 看全部
    其实我一直觉得楼主的品味不错!呵呵!知鸟论坛太棒了!
    回复

    使用道具 举报

    发表于 2023-7-4 03:27:44 | 显示全部楼层
    塞翁364 2023-7-4 03:27:44 看全部
    楼主,大恩不言谢了!知鸟论坛是最棒的!
    回复

    使用道具 举报

    发表于 2023-7-4 06:51:27 | 显示全部楼层
    戏做顿 2023-7-4 06:51:27 看全部
    楼主太厉害了!楼主,I*老*虎*U!我觉得知鸟论坛真是个好地方!
    回复

    使用道具 举报

    • 您可能感兴趣
    点击右侧快捷回复 【请勿灌水】
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则 返回列表

    RSS订阅| SiteMap| 小黑屋| 知鸟论坛
    联系邮箱E-mail:zniao@foxmail.com
    快速回复 返回顶部 返回列表