GC垃圾回收

using System;
using System.Collections.Generic;
using System.Text;

namespace CLRCore
{
    public class GCDemo
    {
        public static void Show()
        {
            //1.什么是GC?
            //  CLR提供的垃圾资源回收器

            //2.什么是垃圾资源?
            //  1.首先是托管资源,其次是引用类型-->引用类型的托管资源。
            //  2.其次是程序访问不到的对象
            //  程序--入口--去找对象--建立对象图--访问不到的就是垃圾

            //3.为什么是引用类型的才被回收?
            //  值类型都存放在栈(线程栈)上,随着线程的生命周期结束而结束
            //  引用类型放在堆上,堆是全局唯一的,所以需要清理垃圾对象
            //  引用类型在堆上是连续分配的,每次分配前都要检查空间够不够分配

            //4.什么是托管/非托管资源?
            //  托管资源,CLR管理的资源,new的对象,各种变量
            //  非托管资源,CLR不能控制的,如数据库链接,打印机连接,文件流,句柄;
            //  非托管资源都是要手动释放的
            //5.为什么很多非托管资源也像托管资源一样用?using()
            //  其实这些非托管资源的释放被封装了,当using结束时自动调用dispose方法

            //6.什么时候执行GC
            //  a)new一个对象时达到临界点时
            //  b)GC.Collect 强制GC
            //  c)程序退出时
            //  频繁GC不好,GC是全局的,会全局阻塞
            //  一般内存过大就检查下静态属性,字段,这些占用的对象不会回收

            //7.回收的过程是怎么样的?
            //  全部对象标记为垃圾--从入口开始遍历所有对象--能访问到的标记可以访问(代+1)
            //  --清理内存,产生不连续的内存--地址移动,变量的地址变了--所以会全局阻塞
            //  清理内存分两种情况:a)无析构函数,直接清理内存;b)有析构函数的,把对象转移到
            //                      一个队列,由专门的析构器线程清理(速度慢)。一般在析构函数
            //                      内释放非托管资源,析构函数由GC调用,不怕程序员忘记  

            //8 垃圾回收策略,分代策略
            //  对象分代
            //  0代:第一次分配到堆就是0代
            //  1代:经历一次GC还在
            //  2代:经历两次或以上
            //  垃圾回收时优先0代,提升回收效率,0代最多也最容易
            //  0代不够找1代--不够在找2代

            //8 大对象堆,大对象堆策略
            //  大于80000字节就是大对象,不分代,都是2代
            //  避免大对象的移动

            //9 析构函数(被动清理)和Dispose()主动清理
            StandardDispose standardDispose = new StandardDispose();
            standardDispose.PublicMathod();
            standardDispose.Dispose();
            standardDispose.PublicMathod();
        }
    }
}
using System;
using System.Collections.Generic;
using System.Text;

namespace CLRCore
{
    public class StandardDispose : IDisposable
    {
        //模拟非托管
        private string _UnmanageResourse = "未被托管的资源";

        //模拟托管
        private string _ManageResourse = "托管的资源";

        //标记是否被释放
        private bool _disposed = false;

        protected virtual void Dispose(bool disposedManage)
        {
            //表示可以被多次释放
            if (_disposed)
            {
                return;
            }

            //清理非托管资源
            if (_UnmanageResourse != null)
                _UnmanageResourse = null;
            if (disposedManage)
            {
                //清理托管资源
                if (_ManageResourse != null)
                    _ManageResourse = null;
            }
            //标记已经被释放
            this._disposed = true;
        }

        public void Dispose()
        {
            this.Dispose(true);//必须是true,GC才会回收
            GC.SuppressFinalize(this);//通知垃圾回收机制不再调用终结器(析构器)
        }

        /// <summary>
        /// 不是必要的,提供一个Close方法是为了符合其他语言的规范(C++)
        /// </summary>
        public void Close()
        {
            this.Dispose();
        }

        /// <summary>
        /// 必须,以备程序员忘记了显示调用Dispose方法
        /// </summary>
        ~StandardDispose()
        {
            //必须是false
            this.Dispose(false);
        }

        public void PublicMathod()
        {
            if (_disposed)
            {
                Console.WriteLine("该对象已经被释放了。。");
                return;
            }
            else
            {
                Console.WriteLine("PublicMathod。。");
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace CLRCore
{
    public class StackHeap
    {
        //堆栈内存分配
        //堆:一个进程运行时,引用类型存放的内存空间,全局唯一
        //栈:先进后出的数据结构,也叫线程栈,一个线程存放值类型的内存空间,随着线程的生命周期

        //值类型分配在栈上:结构  枚举
        //引用类型分配在堆上:类  接口  委托

        public static void Show()
        {
            //所有结构默认继承System.ValueType,结构不能有父类,因为隐式继承这个System.ValueType
            {
                ValuePoint point;// = new ValuePoint();//如果x是属性,必须= new ValuePoint();因为属性必须赋值
                point.x = 123;//x必须赋值后才能使用
                Console.WriteLine(point.x);

                ValuePoint point1 = new ValuePoint();//默认一定有无参构造函数
            }

            {
                ReferencePoint point1 = new ReferencePoint(123);
                //1 new的时候就在栈上开辟内存,创建实例
                //2 把实例的引用传递给构造函数
                //3 执行构造函数
                //4 返回引用

                //值类型的值随着对象而存储
                //引用类型一定出现在堆上
                //因为值类型长度是确定的,引用类型的长度是不定的,也只有堆上能放不定长度的值
                Console.WriteLine(point1.x);
            }

            //装箱拆箱
            {
                int i = 3;
                object oi = i;//装箱,值类型出现在堆上了
                i = (int)oi;//拆箱,堆上的值出现到栈上了
            }

            {
                string str1 = "小王";
                string str2 = "小高";
                str2 = "小王";
                Console.WriteLine(object.ReferenceEquals(str1, str2));//true

                str2 = "大王";
                //字符串在重新赋值时等于重新开辟一块内存放值,原值不变
                //字符串的不可变性
                //为啥不可变?开辟新内存这不是浪费吗?
                //因为堆上的值的内存都是连续摆放的,节省空间嘛。这样的话一个值如果变化,会导致其他变量全部移动,成本太高,还不如新开内存 

                //StringBuild  string.Format  new String() 这几个字符串相同的情况下,引用也是不同的
                Console.WriteLine(str1);

                str2 = new String("小王");
                Console.WriteLine(object.ReferenceEquals(str1, str2));//false
            }

            {
                StackTrace stackTrace = new StackTrace();
                //获取哪个类来调用的
                Type type = stackTrace.GetFrame(1).GetMethod().DeclaringType;
                //获取哪个类的哪个方法来调用的
                string method = stackTrace.GetFrame(1).GetMethod().ToString();
                Console.WriteLine(method);
            }

        }
    }

    public struct ValuePoint //所有结构默认继承System.ValueType,结构不能有父类,因为隐式继承这个
    {
        public int x;
        public ValuePoint(int x)
        {
            this.x = x;
        }
    }

    public class ReferencePoint
    {
        public int x;
        public ReferencePoint(int x)
        {
            this.x = x;
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值