【NET】.NET基础篇- 1. CLR

先说3句人话:

  • CLR(Common Language Runtime)是.NET的托管运行时,类似Java的JVM;
  • 它把"你的代码"->“机器码”->"执行"的过程全部包圆儿;
  • 内存,线程,异常,安全,编译,GC,调试,热更新…这些脏活儿累活儿都是CLR在背后负重前行的;

1.CLR介绍

1.1 CLR在.NET版图里的 位置

在这里插入图片描述
看到GC大宝贝儿了没,就是我们常用常考的。
1.2 CLR的7大核心子系统

子系统职责细节
类加载器(Loader)把程序集、类型、方法搬进内存延迟加载 + AssemblyLoadContext(动态隔离)
JIT 编译器IL → 机器码RyuJIT、分层编译、动态 PGO、OSR
垃圾回收器(GC)自动内存管理分代 + 区域 + 后台服务器 GC
异常系统托管 ↔ 原生异常互通SEH 映射、第一次机会/第二次机会
安全系统验证代码安全性不再 CAS,转为沙箱 + ALC + 文件系统权限
调试/剖析断点、单步、采样ICorDebug、EventPipe、DiagnosticPort
线程 & 同步托管线程、锁、IOCPThreadPool、PortableThreadPool、Work-Stealing

2.CLR-堆和栈

2.1 堆(Heap)堆又叫托管堆,是应用程序运行时,请求操作系统分配给自己的内存空间,存在申请-给予的过程。
特点:

  • 存储引用类型;
  • 受垃圾处理器GC管理;
  • 按地址索引;空间大,访问速度没有栈快;
  • 堆资源在分配的时候是按照顺序连续分配的,因空间有限,所以连续摆放。
    在这里插入图片描述
    2.2 栈
    栈是操作系统建立线程时,为这个线程建立的存储区域。
    特点:
  • 存储值类型;
  • 先进后出;栈是自维护,当元素不再被使用时被抛出;
  • 空间小,访问速度快;
    2.3 C# 在堆栈上分配资源分
    为3种情况:
  1. 通常来讲:值类型分配在栈上,引用类型分配在堆上-地址在栈上;
  2. 值类型中的引用类型(struct中的引用类型成员和变量),分配在堆上-任何时候引用类型都分配在堆上;
  3. 引用类型中的值类型:
    a.如果是类的成员,分配在堆上;
    b. 如果是局部变量,分配在栈上;
    2.4 解析对象内存结构/解析托管堆结构不写了。
    用到和被问到的概率比你吃糖角烫后脑勺的概率还低。

3.CLR-装箱/拆箱

3.1 装箱
装箱是指将值类型转换成引用类型(通常是object类型或者接口类型)的过程。
步骤:

  • 内存分配:在Heap上分配一块内存,用于存储值类型的数据;
  • 复制数据:将值类型的数据从栈复制到堆上新分配的内存中;
  • 返回引用:返回堆上对象的引用;
    3.2 拆箱拆箱是指将引用类型转换回值类型的过程。
    步骤:
  • 检查类型:检查引用类型是否与目标值类型兼容。如果不兼容,会抛出InvalidCastException异常;
  • 复制数据:将堆上的数据复制回栈上的值类型变量;

4.CLR-GC机制

4.1 GC对象垃圾回收的对象就是托管资源。什么是托管资源?

  • 由CLR控制的内存资源就是托管资源,这些资源被CLR进行管理,如程序中分配的对象,作用域内的变量等;大部分对象都是托管资源;
    • 不能被CLR控制的资源就是非托管资源,如文件流,数据库连接,系统的窗口句柄,打印机资源等;这些资源不被GC回收,需要调用自身Dispose方法进行释放;此外,栈里的资源也不需要GC回收,它是自管理。
      4.2 GC步骤就2步。
  1. Mark-Sweep,标记清除阶段- 先假设heap里所有的对象都可以被回收,然后找出不能被回收的(正在被使用的)对象打上标记,最后heap中没有打标记的对象都是可以被回收的;
  2. Compact 压缩整理阶段- 对象被回收之后,heap里的内存空间变得不连续,在heap中移动这些对象,使他们重新从heap的基地址上开始连续排列,类似于空间的碎片整理;

回收前后对比:

  • 内存移动
  • 地址变更(别担心,CLR会自动变更地址,是仍被引用的对象依然有效)地址不会变的情况:大对象堆LOH上的对象(>=85000字节).NET4.5之前不会压缩,只会标记清除,地址不变.NET4.5之后可以选择其中LOH压缩(通过GCSettings.LargeObjectHeapCompactionMode),但默认仍然是不压缩;
  • 阻塞线程
    4.3 GC时机
    4种场景:
  • new对象时-临界点;
  • Windows报告内存不足;
  • GC.Collect强制GC;程序退出或者卸载

4.4 GC模式

2种模式:工作站模式

  • 场景:桌面客户端(WinForm/WPF/MAUI),开发机,单核Pod/边缘容器;
  • 特点:单线程回收,低延迟 + 快速响应,适合UI应用;服务器模式
  • -场景:ASP.NET Core/Web API/gRPC服务,高并发后台服务/消息队列消费者,K8s大容器;单核机器强制退化为工作站模式;
  • 特点:多区域并行回收,高吞吐 + 多核并行,最大化CPU利用率*** 无论哪种模式,都可以再选择"后台策略":
  • 后台工作站模式:后台单线程,Gen2与应用线程交替执行,暂停短;
  • 后台服务器模式:每核1条后台线程,Gen2并行标记,但最终压缩阶段全局STW;你说扯不扯。
    两者差异(看看就得):
维度工作站模式服务器模式
托管堆数量1 个(单堆)每逻辑 CPU 1 个堆(可手动限制)
GC 线程1 条 GC 线程每堆 1 条专用 GC 线程,并行回收
Gen0/1 策略STW(Stop-The-World)时间极短各堆独立并行 STW,时间更短
Gen2 策略默认**后台(并发)**回收,分阶段暂停后台服务器 GC:多线程并行,但全局 STW
内存占用低(几十 ~ 几百 MB)高(默认每堆 256 MB 初始 + 增长)
CPU 占用低,线程少高,并行线程多
暂停时间极短,适合交互式单次暂停略长,但总吞吐高
LOH 压缩默认关闭,可手动开默认关闭,可手动开
容器亲和单核/小内存容器首选多核/大内存容器;.NET 8 支持 DATAS 动态缩堆

4.5 分代策略

  1. 分代
  • 0代:内存区域最小(256k~几MB);存放最新创建对象;GC最频繁;存放于SOH;SWT时间为亚毫秒;
    • 1代:0代中被回收后剩下的对象为1代;存储区域几MB;缓冲带,避免短寿命对象晋升;GC频率中等;存放于SOH;SWT时间<1ms;
    • 2代:1代中被回收后剩下的对象为2代;存储区域GB级;长寿对象(全局缓存,静态数据);GC频率最低;存放于SOH;SWT时间几十ms-秒级;当某代内存不足时,触发该代及其以下所有代的回收。
    1. 大对象 - 分配进大对象堆(LOH)的大对象(>=85000B)直接进入2代,避免复制开销;默认不压缩(.NET4.5可开),不移动,因为成本高;*SOH:小对象堆,small object heap(<85000B);建议以上内容流如背倒,散了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值