随笔分类 -  .NET Core 底层

摘要:常见的思路 内存泄露 托管内存暴涨大多数原因都是因为对象被GC Root(stack,gchandle,finalizequeue)持有,所以一直无法释放,所以观察的重点都在对象的可疑GC Root 上 CPU高 CPU占用率高是由线程抬起来,因此观察线程当时在做什么,调用堆栈上的方法执行了多久是重 阅读全文
posted @ 2025-02-20 14:51 叫我安不理 阅读(1170) 评论(10) 推荐(10)
摘要:C#中的常见集合 注意,箭头线不代表继承关系,只代表功能上的加强,如有错误,欢迎指出。 泛型集合时间复杂度 集合类型 添加 删除 查找 访问(索引/键) 遍历 备注 List<T> O(1)(均摊) O(n) O(n) O(1) O(n) 动态数组;删除/插入中间元素需移动数据 SortedList 阅读全文
posted @ 2025-02-17 17:12 叫我安不理 阅读(923) 评论(0) 推荐(7)
摘要:物理内存与虚拟内存 物理内存(Physical Memory) 定义:物理内存是计算机硬件中的实际RAM(如DDR5内存条),直接通过总线与CPU连接,用于临时存储运行中的程序和数据。 虚拟内存(Virtual Memory) 定义:由操作系统管理的抽象内存层,通过结合物理内存和磁盘空间(如页面文件 阅读全文
posted @ 2025-02-11 17:40 叫我安不理 阅读(1473) 评论(2) 推荐(17)
摘要:简介 CLR的GC模式与JVM的GC模式理念不同,相对JVM的各种小参显得比较简陋,CLR的理念是约定优于配置,并根据程序类型来分提供了几个默认的选项给大家选择。 CS程序默认使用的工作站模式(WorkStation Mode) BS程序默认使用的服务器模式(Server Mode) 不同的模式,堆 阅读全文
posted @ 2025-02-06 10:38 叫我安不理 阅读(803) 评论(4) 推荐(4)
摘要:简介 终于来到了GC的最后一个步骤,在此之间,大量预备工作已经完成。万事俱备,只欠东风 清除 如果GC决定不压缩,它将仅执行清除操作。清除操作非常简单,把所有不可到达对象(gap),转换成Free。也就是转换成空闲内存空间。 由于所有的繁重计算任务在plan_phase阶段均已完成,所以步骤比较简单 阅读全文
posted @ 2025-01-25 10:16 叫我安不理 阅读(702) 评论(2) 推荐(5)
摘要:简介 在mark_phase阶段之后,所有对象都被标记为有用/垃圾对象。此时,垃圾回收器已经拥有启动垃圾回收的所有前置准备工作。 这个时候,垃圾回收期应该执行"清除回收"还是"压缩回收"呢?只有做一下试验才能得出理论支撑。 模拟压缩 这里会有一个悖论,如果你要知道压缩是否划得来,那你就得先压缩后查看 阅读全文
posted @ 2025-01-16 15:15 叫我安不理 阅读(840) 评论(5) 推荐(7)
摘要:简介 C# 采用基于代的回收机制,并使用了更复杂的 链式跟踪算法 来识别对象是否为垃圾。 GC触发的原因 截至到.NET 8,GC触发的原因有18种 enum gc_reason { reason_alloc_soh = 0,//小对象堆,快速分配预算不足 reason_induced = 1,// 阅读全文
posted @ 2025-01-13 12:23 叫我安不理 阅读(658) 评论(0) 推荐(5)
摘要:对象分配策略 .NET程序的对象是由CLR控制并分配在托管堆中,如果是你,会如何设计一个内存分配策略呢? 按需分配,要多少分配多少,移动alloc_ptr指针即可,没有任何浪费。缺点是每次都要向OS申请内存,效率低 预留缓冲区,降低了向OS申请内存的频次。但在多线程情况下,alloc_ptr锁竞争会 阅读全文
posted @ 2025-01-06 17:09 叫我安不理 阅读(951) 评论(2) 推荐(12)
摘要:C#源码到汇编的过程 在类型系统之前,我们先来了解一下C#的源码是如何一步一步被编译成机器码的 C#源码被Roslyn编译器编译成DLL DLL中包含了MetaData与IL Code 先由加载器根据MetaData构建出类型系统的数据结构 再由JIT编译器根据IL Code,懒加载式的生成汇编等 阅读全文
posted @ 2024-12-24 12:14 叫我安不理 阅读(745) 评论(2) 推荐(19)
摘要:中断的基础知识 https://www.cnblogs.com/lmy5215006/p/18816120 用户异常 C#的异常,在Windows平台下是完全围绕SEH处理框架来展开。在Linux上则是围绕signal模拟成SEH结构,因为都会进入内核态,所以其开销并不低,内部走了很多流程。 sta 阅读全文
posted @ 2024-12-17 17:34 叫我安不理 阅读(1095) 评论(4) 推荐(16)
摘要:.Net托管堆布局 加载堆 主要是供CLR内部使用,作为承载程序的元数据。 HighFrequencyHeap 存放CLR高频使用的内部数据,比如MethodTable,MethodDesc. 通过is判断类型之间的继承关系,调用接口的方法和虚方法,都需要访问MethodTable LowFrequ 阅读全文
posted @ 2024-12-11 15:20 叫我安不理 阅读(1698) 评论(1) 推荐(24)
摘要:CPU原子操作 原子操作,指一段逻辑要么全部成功,要么全部失败。概念上类似数据库事物(Transaction). CPU能够保证单条汇编的原子性,但不保证多条汇编的原子性 那么在这种情况下,那么CPU如何保证原子性呢?CPU本身也有锁机制,从而实现原子操作 眼见为实 int location = 1 阅读全文
posted @ 2024-12-05 17:45 叫我安不理 阅读(3255) 评论(11) 推荐(26)
摘要:简介 多线程与异步是两个完全不同的概念,常常有人混淆。 异步 异步适用于"IO密集型"的场景,它可以避免因为线程等待IO形成的线程饥饿,从而造成程序吞吐量的降低。 其本质是:让线程的cpu片不再浪费在等待上,期间可以去干其它的事情。 要注意的是:Async不能加速程序的执行,它只能做到不阻塞线程。 阅读全文
posted @ 2024-11-29 15:10 叫我安不理 阅读(3300) 评论(6) 推荐(20)
摘要:简介 上文提到,创建线程在操作系统层面有4大无法避免的开销。因此复用线程明显是一个更优的策略,且降低了使用线程的门槛,提高程序员的下限。 .NET Core线程池日新月异,不同版本实现都有差别,在.NET 6之前,ThreadPool底层由C++承载。在之后由C#承载。本文以.NET 8.0.8为蓝 阅读全文
posted @ 2024-11-25 17:00 叫我安不理 阅读(3624) 评论(10) 推荐(38)
摘要:简介 内核态,用户态,线程,进程,协程基本概念不再赘述。 原生线程和用户线程 原生线程 在内核态中创建的线程,只服务于内核态 用户线程 由User Application创建的线程,该线程会在内核态与用户态中间来回穿梭 比如Throw Exception,就会由CLR 线程触发,从用户态切换到内核态 阅读全文
posted @ 2024-11-22 14:02 叫我安不理 阅读(1407) 评论(7) 推荐(14)
摘要:简介 烂大街的资料不再赘述,简单来说就是给代码看的注释 Attribute的使用场景 Attribute不仅仅局限于C#中,在整个.NET框架中都提供了非常大的拓展点,任何地方都有Attribute的影子 编译器层 比如 Obsolete,Conditional C#层 GET,POST,Max,R 阅读全文
posted @ 2024-11-19 16:37 叫我安不理 阅读(2063) 评论(1) 推荐(11)
摘要:简介 反射,反射,程序员的快乐。 前期绑定与后期绑定 在.NET中,前期绑定(Early Binding)是指在编译时就确定了对象的类型和方法,而后期绑定(Late Binding)或动态绑定是在运行时确定对象的类型和方法。 前置知识:C#类型系统结构 C#作为C++++ ,在类型系统上沿用C++的 阅读全文
posted @ 2024-11-15 09:29 叫我安不理 阅读(2750) 评论(4) 推荐(31)
摘要:简介 .NET通过委托来提供回调函数机制,与C/C++不同的是,委托确保回调是类型安全,且允许多播委托。并支持调用静态/实例方法。 简单来说,C++的函数指针有如下功能限制,委托作为C#中的上位替代,能弥补函数指针的不足。 类型不安全 函数指针可以指向一个方法定义完全不同的函数。在编译期间不检查正确 阅读全文
posted @ 2024-11-13 10:18 叫我安不理 阅读(1532) 评论(0) 推荐(16)
摘要:简介 泛型参考资料烂大街,基本资料不再赘述,比如泛型接口/委托/方法的使用,逆变与协变。 泛型好处有如下几点 代码重用 算法重用,只需要预先定义好算法,排序,搜索,交换,比较等。任何类型都可以用同一套逻辑 类型安全 编译器保证不会将int传给string 简单清晰 减少了类型转换代码 性能更强 减少 阅读全文
posted @ 2024-11-07 14:57 叫我安不理 阅读(3526) 评论(2) 推荐(34)