欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

CLRCore(CLR核心机制)

程序员文章站 2022-08-08 16:29:59
JIT--第一次--标记已--存根--调用--查找存根--执行机器码 C#和CIL的关系: C#和N#都是CIL实现,但是彼此不能互通: C#和N#公开不分满足规范,我们才能互通 CLS就是描述多语言互通的规范 内存分配:线程栈 堆Heap: 一个程序运行时,该进程存放引用类型变量的一块内存,全局唯 ......

CLRCore(CLR核心机制)

 

jit--第一次--标记已--存根--调用--查找存根--执行机器码

CLRCore(CLR核心机制)

 

 

c#和cil的关系:

CLRCore(CLR核心机制)

 

 c#和n#都是cil实现,但是彼此不能互通:

CLRCore(CLR核心机制)

 

 c#和n#公开不分满足规范,我们才能互通

CLRCore(CLR核心机制)

 

 cls就是描述多语言互通的规范

CLRCore(CLR核心机制)

 

 

内存分配:线程栈

  堆heap:

    一个程序运行时,该进程存放引用类型变量的一块内存,全局唯一!只有一个堆

  栈stack:

    数据结构,先进后出,线程栈,一个线程存放变量的内存(一个线程有一个)

  值类型分配在栈上,比如结构、枚举、int等

  引用类型分配在堆上,比如类、接口、委托等

引用类型

  1、调用new的时候,就会去栈上开辟内存,创建实例。这就是为什么在构造函数中跨域使用this

  2、把实例的引用传递给构造函数

  3、执行构造函数

  4、返回引用

装箱拆箱

int i=3;
obect obj=i;//装箱
int k=(int)obj;//拆箱

引用类型在哪里?值类型在哪里?

  值类型的值,会随着对象的位置存储。引用类型的值,一定在堆里面。值类型的长度是确定的,引用类型的长度是不确定的,只有堆才能放各种值。

  下面有一个例子:

public class mytest
{
    private int x;
    public mytest(int n)
    {
        this.x=n;
    }
}
mytest t=new mytest(3);//引用类型

  那么,t.x  这个3,是存放在哪里呢?是堆上还是栈上?

    ===.》出现在堆里面,因为值类型的属性,会随着对象的位置存储

 public struct valuepoint// : system.valuetype  结构不能有父类,因为隐式继承了valuetype
 {
     public int x;
     public valuepoint(int x)
     {
         this.x = x;
         this.text = "1234";
     }

     public string text;//堆还是栈?
 }

  struct是值类型,但是里面的text,是存放在堆还是栈?答案是,对立面,因为引用类型的值,一定出现在堆里面。

 

string字符串内存分配

string student = "bingle1";
string student2 = student;

console.writeline(student);//bingle1
console.writeline(student2);//bingle1

student2 = "bingle2";//=new string(app);
console.writeline(student);//bingle1
console.writeline(student2);//bingle2
console.readline();
string student = "bingle1";
string student2 = "bingle2";//共享
student2 = "bingle1";

console.writeline(object.referenceequals(student, student2));//true

为什么是true?因为同一个变量,享元分配内存。为什么享元?节约内存。

student2 = "binglebingle";//等于重新开辟一块内存叫“binglebingle”  new string("binglebingle")
console.writeline(student);//bingle1

还是bingle1,为什么?因为字符串的不可变性。为什么字符串不可以变,开辟新内存不浪费吗?因为在堆上是连续拜访的,如果有变化,会导致其他变量全部移动,成本太高,还不如重新new一个。

string student3 = string.format("bing{0}", "le");
console.writeline(object.referenceequals(student, student3));//false

为什么是false?没有享元。分配地址,然后计算,才知道是"bingle"。

 string student4 = "bing" + "le";
 console.writeline(object.referenceequals(student, student4));//true
 //true  编译器优化了,直接就是大山
string halfstudent = "le";
string student5= "bing" + halfstudent;
console.writeline(object.referenceequals(student, student5));
//false 也是先内存,再计算

东西放在站上速度快,但是值类型是不能继承的,长度也有限。

垃圾回收---clr提供gc,托管堆垃圾回收

  1、什么样的对象需要垃圾回收?

    托管资源+引用类型。线程栈的是不需要垃圾回收的,用完立马就回收了。

  2、托管资源和非托管资源

    托管资源的就是clr控制的,new的对象、string字符串。非托管就不是clr控制的,数据库连接、文件流、句柄、打印机连接。using(sqlconnection)//被c#封装了管道了那个非托管的数据库连接资源。只要手动释放的,都是非托管的。

  3、哪些对象的内存,能被gc回收?

    对象访问不到了,那就可以被回收了。程序----入口----去找对象---建立对象图----访问不到的就是垃圾,就可以回收了。

  4、对象是如何分配在堆上的?

    连续分配在堆上的,每次分配就先检查空间够不够。

CLRCore(CLR核心机制)

 

   5、什么时候执行gc?

    a、new对象的时候----临界点

    b、gc.collection(),这个方法会强制gc

    c、程序退出时会gc

    a="123"

    a=null

    gc.collect 可以gc,但是频繁gc是不好的,gc是全局的

    项目中有6个小时才运行new一次,什么时候gc? 不gc,可以手动gc

  6、gc的过程是怎么样的?

    n个对象,全部标机wie垃圾,入口开始遍历,访问到的就标机可以访问(+1),遍历完就清理内存,产生不连续的内存,压缩,地址移动,修改变量指向,所以全局会阻塞。

    清理内存分两种情况:

      a、无析构函数,直接清理内存

      b、把对象转到一个单独的队列,会有一个析构函数专门做这个。通常在析构函数内部是用来做非托管资源释放,因为clr肯定调用,所以避免使用者忘记的气矿。

  7、垃圾回收策略

CLRCore(CLR核心机制)

 

     对象分代:3代

    0代:第一次分配到堆,就是0代

    1代:经历了一次gc,还存在的

    2代:经历了两次或以上的gc,还存在的。

    垃圾回收时,优先回收0代,提升小路,最多也最容器释放。0代不够,找1代,1代不够找2代,再不够就不用了。。。代的数值越大,越难回收。

    大对象堆:一是内存移动大对象;二是0代空间问题。80000字节就叫大对象,没有分代,直接都是2代。

    那么,静态资源在程序退出的时候,会gc吗?答案是,会的。

 

析构函数:被动清理;dispose:主动清理

    

 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");
         }
         //
     }