JIT--第一次--标记已--存根--调用--查找存根--执行机器码程序员
C#和CIL的关系:数据库
C#和N#都是CIL实现,可是彼此不能互通:跨域
C#和N#公开不分知足规范,咱们才能互通数据结构
CLS就是描述多语言互通的规范函数
内存分配:线程栈优化
堆Heap:this
一个程序运行时,该进程存放引用类型变量的一块内存,全局惟一!只有一个堆spa
栈Stack:线程
数据结构,先进后出,线程栈,一个线程存放变量的内存(一个线程有一个)3d
值类型分配在栈上,好比结构、枚举、int等
引用类型分配在堆上,好比类、接口、委托等
引用类型
一、调用new的时候,就会去栈上开辟内存,建立实例。这就是为何在构造函数中跨域使用this
二、把实例的引用传递给构造函数
三、执行构造函数
四、返回引用
装箱拆箱
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 编译器优化了,直接就是bingle
string halfStudent = "le"; string student5= "bing" + halfStudent; Console.WriteLine(object.ReferenceEquals(student, student5)); //false 也是先内存,再计算
东西放在站上速度快,可是值类型是不能继承的,长度也有限。
垃圾回收---CLR提供GC,托管堆垃圾回收
一、什么样的对象须要垃圾回收?
托管资源+引用类型。线程栈的是不须要垃圾回收的,用完立马就回收了。
二、托管资源和非托管资源
托管资源的就是CLR控制的,new的对象、string字符串。非托管就不是CLR控制的,数据库链接、文件流、句柄、打印机链接。using(SqlConnection)//被C#封装了管道了那个非托管的数据库链接资源。只要手动释放的,都是非托管的。
三、哪些对象的内存,能被GC回收?
对象访问不到了,那就能够被回收了。程序----入口----去找对象---创建对象图----访问不到的就是垃圾,就能够回收了。
四、对象是如何分配在堆上的?
连续分配在堆上的,每次分配就先检查空间够不够。
五、何时执行GC?
a、new对象的时候----临界点
b、GC.Collection(),这个方法会强制GC
c、程序退出时会GC
a="123"
a=null
GC.Collect 能够GC,可是频繁GC是很差的,GC是全局的
项目中有6个小时才运行new一次,何时GC? 不GC,能够手动GC
六、GC的过程是怎么样的?
N个对象,所有标机Wie垃圾,入口开始遍历,访问到的就标机能够访问(+1),遍历完就清理内存,产生不连续的内存,压缩,地址移动,修改变量指向,因此全局会阻塞。
清理内存分两种状况:
a、无析构函数,直接清理内存
b、把对象转到一个单独的队列,会有一个析构函数专门作这个。一般在析构函数内部是用来作非托管资源释放,由于CLR确定调用,因此避免使用者忘记的气矿。
七、垃圾回收策略
对象分代:3代
0代:第一次分配到堆,就是0代
1代:经历了一次GC,还存在的
2代:经历了两次或以上的GC,还存在的。
垃圾回收时,优先回收0代,提高小路,最多也最容器释放。0代不够,找1代,1代不够找2代,再不够就不用了。。。代的数值越大,越难回收。
大对象堆:一是内存移动大对象;二是0代空间问题。80000字节就叫大对象,没有分代,直接都是2代。
那么,静态资源在程序退出的时候,会GC吗?答案是,会的。(其实回收的不是变量,是某个对象所占据的内存,若是存在一个对象,指向它的引用变量的数量为0,那个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"); } // }