• 7语法基础_CLR核心解析


    CLR的核心功能:内存管理,程序集加载,安全性,异常处理,线程同步等等。可以被很多属于微软系列的开发语言使用。

    堆栈内存分配:

    堆 Heap: 进程堆,一个程序在运行是,进程对方引用类型变量的一块内存,全局唯一
    栈 Stack: 线程栈,一个线程存放变量的一个内存,随着线程的生命周期存在的

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

    {  //内存分配:线程栈   堆
                    ValuePoint valuePoint;
                    valuePoint.x = 123;
                    Console.WriteLine(valuePoint.x);//赋值后才能使用
    
                    ValuePoint point = new ValuePoint();//默认一定有无参数构造函数
                }
               
                {  //装箱拆箱
                    int i = 3;
                    object oValue = i;//装修 值类型转引用类型
                    int k = (int)oValue;//拆箱 引用类型转值类型
                }
                {//new一个对象的步骤
                    ReferenceTypeClass referenceTypeClassInstance = new ReferenceTypeClass();
                    referenceTypeClassInstance.Method(); 
                    //1  调用New  就会去先开辟内存
                    //2  把实例传递给构造函数
                    //3  执行构造函数
                    //4  引用返回
                }
                //值类型的值,会随着对象的位置存储
                //引用类型的值,是一定会存储在堆里面 
                //值类型的长度是确定,引用类型的长度不确定的,只有堆才能存放各种值
    
                {
                    string student = "大山";
                    string student2 = "APP";//共享
                    student2 = "大山"; 
                    Console.WriteLine(object.ReferenceEquals(student, student2)); //判断二者是不是同 
                    // 输出 true  student和student2指向的是同一个引用地址  享元模式
                   
                    student2 = "大山1"; // new String("大山1")  会开辟一块新的内存 
                    Console.WriteLine(student); 
                    //还是输出大山 字符串的不可变性  
                      
                    string student3 = string.Format("大{0}", "");
                    Console.WriteLine(object.ReferenceEquals(student, student3));
                    //false  因为二者没有享元  先分配内存   然后计算  最终的结果才是 “大山”
    
    
                    string student4 = "" + "";
                    Console.WriteLine(object.ReferenceEquals(student, student4));
                    //true  先计算了,  直接就得到大山  可以指向之前存在的内存块
                     
                    string halfStudent = "";
                    string student5 = "" + halfStudent;
                    Console.WriteLine(object.ReferenceEquals(student, student5));
                    //false    是先分配内存,然后再计算
                }

    托管堆垃圾回收 -- GC
    1.值类型和引用类型在GC的区别

      只有引用类型才需要垃圾回收 存放在托管堆上  值类型是存放在栈上的 一直存在内存中


    2.托管资源和非托管资源的区别

      托管在CLR上 如:new的对象,string
      非托管资源:数据连接,文件流,句柄 非托管资源是需要手手动释放;
      using 其实是c# 封装了非托管资源的连接

    3.什么对象的内存,会被GC回收
      对象访问不到了,就可以被GC回收
      程序入口--找对象--建立一个标记--对象图---如果访问不到的就是垃圾

    4.对象是如何分配再堆上
       引用类型每次分配在堆上面的时候回检查当前空间是否足够   足够就分配,不足够就执行GC

    5.什么时候会执行GC

      1 程序在退出的时候会自动执行GC 
      2 string a="value"  设置 a=null; 会执行GC
      3 创建对象的时候--会有一个临界点 当0代对象内存满了 GC会自动去清理0代对象
      4 可以手动触发 GC.Conllect 然后直接执行GC 但是不建议频繁的去GC  因为回收也是需要消耗资源的





    6.GC回收流程
      首先将所有对象--全部对象标记为垃圾--开始一个一个检查,如果可以访问到,就标记一下为不是垃圾对象
      然后会再次遍历去清除内存 清除之后产生不连续内存---然后进行地址移动--在压缩--最后修改变量指向


    7.垃圾回收的策略
      对象分代:3代
      0代: 第一次分配到堆 就是0代
      1代: 被回收一次之后就由0代变成1代,依然存在
      2代: 被回收两次之后就由1代变成2代,依然存在

      优先回收0代,提高效率,最容易也是多需要回收的
      如果0代回收之后,内存仍然不够----就去找1代 -----2代

    8.大对象:所存储的大小大于等于80000个字节的时候,同时大对象会被直接列举为2代

    Dispose 主动清理 析构函数:被动清理

    适用场景就是:数据库连接,文件流 

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace MyCLRCore
    { 
        /// <summary>
        /// 标准Dispose模式
        /// 
        /// 析构函数:被动清理
        /// Dispose:主动清理
        /// </summary>
        public class StandardDispose : IDisposable
        {
            //演示创建一个非托管资源
            private string _UnmanageResource = "未被托管的资源";
            //演示创建一个托管资源
            private string _ManageResource = "托管的资源";
    
    
            private bool _disposed = false;
    
            /// <summary>
            /// 实现IDisposable中的Dispose方法
            /// </summary>
            public void Dispose()
            {
                this.Dispose(true); //必须为true
                GC.SuppressFinalize(this);//通知垃圾回收机制不再调用终结器(析构器)
            }
    
            /// <summary>
            /// 不是必要的,提供一个Close方法仅仅是为了更符合其他语言(如C++)的规范
            /// </summary>
            public void Close()
            {
                this.Dispose();
            }
    
            /// <summary>
            /// 必须,以备程序员忘记了显式调用Dispose方法
            /// </summary>
            ~StandardDispose()
            {
                //必须为false
                this.Dispose(false);
            }
    
            /// <summary>
            /// 非密封类修饰用protected virtual
            /// 密封类修饰用private
            /// </summary>
            /// <param name="disposing"></param>
            protected virtual void Dispose(bool disposing)
            {
                if (this._disposed)//已经被释放的还可以不异常
                {
                    return;
                }
                if (disposing)
                {
                    // 清理托管资源
                    if (this._ManageResource != null)
                    {
                        //Dispose
                        this._ManageResource = null;
                    }
                }
                // 清理非托管资源
                if (this._UnmanageResource != null)
                {
                    //Dispose  conn.Dispose()
                    this._UnmanageResource = null;
                }
                //让类型知道自己已经被释放
                this._disposed = true;
            }
    
            public void PublicMethod()
            {
                if (this._disposed)
                {
                    throw new ObjectDisposedException("StandardDispose", "StandardDispose is disposed");
                }
                //
            }
        }
    }
  • 相关阅读:
    数据结构与算法复习(三)归并排序
    编程练习-扑克牌
    编程练习-字符串处理及简单排序
    spi驱动框架学习记录
    mt7628网口引脚设置成通用GPIO的方法
    数据结构与算法复习(二)插入排序
    数据结构与算法复习(一)快速排序
    基于input子系统的按键驱动程序
    基于设备树编写按键中断驱动程序
    Linux读写权限整理 --chmod
  • 原文地址:https://www.cnblogs.com/LZXX/p/13153815.html
Copyright © 2020-2023  润新知