C#.Net学习笔记——CLR核心机制

news2024/11/17 5:42:24

一、CLR基本介绍

(1)C(Common) L(Language) R(Runtime) IL的运行环境

(2)从下图可以看到,我们的计算机会先把我们写的语言,编写成IL语言,再给计算机去读取。为什么我们不直接把我们的语言编写成计算机能够读取的?主要是考虑到我们计算机的不同,比如32位和64位,他们接收到计算机指令都是不一样的。甚至在不同的操作环境下得出的结果也是不一样的。因此,我们就需要有一个中间语言ILCLR(通用语言进行时)就是IL的运行环境。

(3)metadata清单数据,里面是描述了dll或者exe内有什么东西,依赖了什么东西。

(4)Exe文件的运行。实际上我们的exe文件可以运行,都是由CLR完成的,它为我们加载exe,检查metadata清单和IL。最后JIT(运行时编译)会交给计算机去执行。所以说CLR本质上可以说是一个IL的运行环境。

(5)编译器只要满足CLS规范,编译出来的东西就可以转换成IL语法

(6)使用CLR需要安装.Net Framework

、堆栈内存分配

(1)基本介绍

什么内存?        程序运行时,进程占有的内存

谁来分配?        CLR来分配

1、值类型:struct  枚举

2、引用类型:class  接口  委托

线程栈:栈-stack 先进后出的数据结构,随着线程而分配的,默认执行方法分配1M内存

对象堆:内存,进程中独立画出来的一块内存,有一些对象是不释放的,有些对象需要重用的。类似这种我们就需要堆空间。

 (2)关于Struct 

通过反编译我们可以看到,struct在中间语言里实际上也是class,但是它继承了父类System.ValueType。也就是说,只要是继承了ValueType的,我们就可以认为是值类型

1、对于结构体,我们可以把它当作一个变量直接声明,也可以通过构造函数的方式new出来(结构体的构造函数必须包含所有字段和属性),但是无论哪种方式它都是值类型

  (3)关于Class

引用类型分布在堆上面,变量(左边)是在栈上的,值(右边)是在堆上的

1、new的时候去堆开辟内存,分配一个地址

2、调用构造函数(因为在构造函数里可以使用this),才执行构造函数

3、把引用传给变量

问题思考:

我们有一个类(ReferenceTypeClass),这个类有一个字段int valueTypeField和一个方法Method,方法Method内又声明了一个int valueTypeLocalVariable类型的字段。请问ValueTypeFieldValueTypeLocalVariable分别位于堆还是栈?

答案:valueTypeField是位于堆里,valueTypeLocalVariable是位于栈里。

因为对象都在堆里,那么对象里面的属性也在堆里。而方法内声明的变量是在栈里,当调用我们的方法的时候,线程栈会给声明一个临时变量,是一个全新的局部变量。

总结:方法的局部变量:根据变量自身决定,跟所在环境没关系

           对象是引用类型,其属性/字段都在堆里面

           对象是值类型,其属性/字段,值类型就在栈里,引用类型就在堆里。

引用类型任何时候都在堆里;值类型都在栈里,除非值类型所在对象是在堆里。

、拆箱装箱(浪费性能)

1、装箱:值类型->引用类型

int i = 3;
object Value = i;

2、拆箱:引用类型->值类型

object Value = 10;
int k = (int)Value;

3、拆箱装箱只能发生在父子类里面?因为这样才能转换。

四、特别对象——字符串

1、string是一个引用类型

思考1:string是一个引用类型,下面例子中声明了一个student和student2。student2=student,使得他们指向同一内存 “哈哈” 。但是为什么在student2赋新值后student不会跟着改变。

   private void button17_Click(object sender, EventArgs e)
        {
            string student = "哈哈";
            string student2 = student;
            Log.Info(student + " " + student2);
            student2 = "1234";
            Log.Info(student + " " + student2);
        }

答案:因为赋值其实new了一个新的string,重新开辟内存,返回引用。

        改了student2的值,但不是修改内存;string字符串的内存是不可变的

思考2:看案例,student和student2都是指向不同的内存,当我们重新给studeng2赋值并且这个值与student的值相等。按照上面的理论,他们的指向应该都是各自的内存,只不过他们的值恰好相等。思考一下他们都指向哪?

        private void button17_Click(object sender, EventArgs e)
        {
            string student = "哈哈";
            string student2 = "呵呵";
            student2 = "哈哈";
            Log.Info(object.ReferenceEquals(student, student2));
        }

答案:实际上他们还是指向了同一片内存。这就是我们CLR的机制,CLR内存分配字符串的时候,会查找相同值,有就重用。因此他们会指向相同内存以节约内存。

不可变是因为享元,可能有多个变量指向同一字符串,字符串变化了,多个变量都会受影响。

还因为堆里面的内存是连续分配的,如果变长度,会导致大量数据的移动。所以不如重新分配一个。

五、垃圾回收

(1)产生垃圾的原因:

1、值类型出现在线程栈:用完自己就结束,变量-值类型都会释放的。

2、引用类型出现在堆里:全局就一个堆,空间有限,所以才需要垃圾回收。

3、操作系统里面,内存是链式分配的,可能有碎片

4、CLR堆里边:连续分配(数组),空间有限,节约空间

(2)GC发生时机:

1、GC发生在New的时候,New一个对象时,会开辟内存在堆里边

2、New的时候看看空间够不够,不够的话就要GC了

3、定时程序,24小时执行一次,但是对象不会被回收,因为24小时之后你才会new,这个才能发生GC

4、静态不可能被回收 静态持有的引用也不会被回收

5、类似于下图这种情况,我们写了一个方法,方法内声明了Student和Class和一个int类型的变量。当方法执行结束后,值类型的i就会被直接回收,而引用类型的new Class则丢失引用,但是内存不会被自动回收,产生GC。

     private static Student _student = new Student()
        {
            Id = 1,
            Name = "Test",
        };
        public static void Show()
        {
            Student student = _student;
            Class @class = new Class()
            {
                Id = 1,
                CLassName = "Test",
            };
            int i = 3;  //会被GC
        }

6、主动GC

GC.Collect();

怎么回收?

什么是垃圾?垃圾是完全访问不到的东西

new的时候发现内存不够了,就去遍历所有堆的对象,标记访问不到,然后启动一个线程来清理内存。

移除标记了的对象,其他挪动,然后整齐摆放,所有这个时候全部线程停止,不允许操作内存。

为了促进垃圾回收,把对象赋值成null。其实不对,没有意义,垃圾回收是因为访问不到

 六、优化策略

1、首次GC前,全部对象都是0级。

2、第一次GC后,还保留的对象叫1级

3、回收先找1级对象,如果空间还不够,再去找1级对象,这之后,还存在的对象变成2级,2级还不够就内存溢出了

4、越是最近分配的,越是会被回收。比如for循环创建对象

因为回收过了,之前的内存可能是常驻内存,所以就从最近开始回收。

  七、析构函数

1、~Student 析构函数是用来释放非托管资源的,等着GC的时候去把非托管资源释放掉,系统自动执行。非托管资源就是管理不到的一些资源,包括数据库连接、打开的文档等。

 八、Using

1、下面可以说是等同关系,Using本质上来说只是一种语法糖

using(Student student = new Student())
{
    Id = 234
}
try
{
    Student student = new Student()
    {
        Id=234
    }
}
finally
{
    //调用的dispose()
}

2、Dispose() 主动释放,方法本身是没有意义的,我们需要在方法里面实现堆资源的释放

     而不是说对象释放的时候会自动去调用Dispose方法。

3、GC不会调用,而是用对象时,使用者主动调用这个方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1368489.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

伺服电机:伺服电机的控制模式

一、伺服电机基本的控制模式 在AC伺服系统中,对编码器所发出的脉冲信号或伺服电机的电流进行检测,将检测结果反馈给伺服驱动器,伺服驱动器根据检测结果和相应的控制指令,对伺服电机进行相应的控制,根据指令的不同&…

LeetCode(704)二分查找⭐

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 示例 1: 输入: nums [-1,0,3,5,9,12], target 9 输出: 4 解释: 9 出现…

html+css 文本样式常用属性集合和总结

文本样式 text-transform transform 的意思是使变形 值描述none默认。定义带有小写字母和大写字母的标准的文本capitalize文本中的每个单词以大写字母开头uppercase定义仅有大写字母lowercase定义无大写字母,仅有小写字母inherit规定应该从父元素继承 text-trans…

邮政快递单号查询入口,对快递单号进行提前签收分析

一款优秀的快递单号筛选软件能够给你的工作和生活带来极大的便利。通过合理选择和使用该软件,你将能够轻松管理、高效筛选快递单号,提升工作效率和生活品质。不妨试试我们的【快递批量查询高手】,让你的物流管理更加智能、便捷! …

UDP 和 TCP 、HTTP、HTTPS、SOCKS5协议的不同之处及应用场景

UDP 和 TCP、HTTP、HTTPS、SOCKS5 协议的不同之处及应用场景: UDP (User Datagram Protocol): 不同之处:UDP 是无连接的,不保证数据包的顺序到达或完整性,也没有流量控制和拥塞控制机制。它尽可能快地将数据包从源主机…

Linux--好玩的进度条

前言 先来看看我们想要达到的进度条效果,具体代码会在文章最后面放出。 一、创建文件及Makefile 我们需要实现声明的定义的分离,因此创建如下三个文件。 process.h prcess.c main.c。 touch process.h process.c main.c 同时还需要创建Makefi…

钡铼技术推出注塑机OPC UA网关,助力注塑机行业转型升级

前言 “工欲善其事,必先利其器”,塑料行业也是一样,注塑机就是塑料行业最重要的“器”之一。 “ OPC UA 如果你的注塑应用支持OPC UA无疑会有广泛的适配性。 OPC UA作为工业4.0中一个重要的通信协议(IEC 62541)&am…

MySQL高可用解决方案演进:从主从复制到InnoDB Cluster架构

💂 个人网站:【 海拥】【神级代码资源网站】【办公神器】🤟 基于Web端打造的:👉轻量化工具创作平台💅 想寻找共同学习交流的小伙伴,请点击【全栈技术交流群】 当谈论MySQL高可用性解决方案时,从…

密码学(三)

文章目录 前言一、Software Attestation Overview二、Authenticated Key Agreement三、The Role of Software Measurement 前言 本文来自 Intel SGX Explained 请参考: 密码学(一) 密码学(二) 一、Software Attesta…

kubernetes Adminssion Webhook 准入控制器 (ImagePolicyWebhook)

开头语 写在前面:如有问题,以你为准, 目前24年应届生,各位大佬轻喷,部分资料与图片来自网络 介绍 原理 流程 Admission Webhook 准入控制器Vebhook是准入控制插件的一种,用于拦截所有向APISERVER发送的…

企业提升客户体验的实用技巧与策略

什么是客户体验?通俗点说,他是客户和企业在互动过程中收获的感受和印象。这个过程包括接触、预购、购买、使用、售后整个阶段。 联想到我们自己购买产品的过程,对一家店或者品牌的感受,绝不仅仅从产品的功能体验感和质量上获得的…

如何在Android Glide中结合使用CenterCrop和自定义圆角变换(图片部分圆角矩形)

如何在Android Glide中结合使用CenterCrop和自定义圆角变换(图片部分圆角矩形) 在Android开发中,使用Glide加载图片时,我们经常需要对图片进行特定的处理,比如裁剪和圆角变换,特别是一些设计稿,…

【51单片机】点亮第一个LED灯(含创建文件等基础操作)

51单片机现在不仅是电子信息专业学生的必修课,也是进入嵌入式领域的踏脚石。 本系列将会按照江科大的视频进行,也算是相当于一个笔记,进行巩固 实现第一个LED灯的点亮其实并不复杂,重要的是有一些准备工作比较繁琐,就…

关于“Python”的核心知识点整理大全63

目录 20.2.11 使用 Git 跟踪项目文件 1. 安装Git 2. 配置Git 3. 忽略文件 .gitignore 注意 4. 提交项目 20.2.12 推送到 Heroku 注意 20.2.13 在 Heroku 上建立数据库 20.2.14 改进 Heroku 部署 1. 在Heroku上创建超级用户 注意 注意 20.2.11 使用 Git 跟踪项目文件…

两种方式实现mysql截取年月日

select date_format(now(), %Y-%m-%d) select substring(now(), 1, 10)

MySQL面试题(下)

一.面试题案例 二.思维导图 一.面试题案例 1.查询学过「张三」老师授课的同学的信息 select s.*,c.cname,t.tname,sc.score from t_mysql_teacher t, t_mysql_course c, t_mysql_student s, t_mysql_score sc where t.tidc.cid and c.cidsc.cid and sc.sids.sid and t.tnam…

使用 TypeVar 创建 Self 类型变量,方便用户在 Pycharm 编辑器中链式调用校验方法

目录 一、前置说明1、总体目录2、相关回顾3、本节目标 二、操作步骤1、项目目录2、代码实现3、测试代码4、日志输出 三、后置说明1、要点小结2、下节准备 一、前置说明 1、总体目录 《 pyparamvalidate 参数校验器,从编码到发布全过程》 2、相关回顾 使用 Raise…

linux centos 账户管理命令

在CentOS或其他基于Linux的系统上,账户管理涉及到用户的创建、修改、删除以及密码的管理等任务。 linux Centos账户管理命令 1 创建用户: useradd username 这将创建一个新用户,但默认不会创建家目录。如果想要创建家目录,可以…

Mac电脑好用的修图软件:Affinity Photo 2中文 for Mac

Affinity Photo 2提供了广泛的图像编辑和调整工具,使用户能够对照片进行精确的编辑和改进。它支持图像裁剪、旋转、缩放、变形等操作,以及曝光、色彩、对比度、饱和度等调整。 非破坏性编辑:软件采用非破坏性编辑方式,即对原始图…

[足式机器人]Part3 机构运动学与动力学分析与建模 Ch00-2(1) 质量刚体的在坐标系下运动

本文仅供学习使用,总结很多本现有讲述运动学或动力学书籍后的总结,从矢量的角度进行分析,方法比较传统,但更易理解,并且现有的看似抽象方法,两者本质上并无不同。 2024年底本人学位论文发表后方可摘抄 若有…