托管堆和垃圾回收


  托管堆基础

 1.调用IL指令newobj,为代表资源的类型分配内存。
  2.初始化内存,设置资源的初始状态并使资源可用。类型的实例构造器负责设置初始状态。
  3.访问类型的成员来使用资源(有必要可以重复)。
  4.摧毁资源的状态以进行清理。
  5.释放内存。垃圾回收器独自负责这一步。

托管堆分配资源

 CLR要求所有对象都从托管堆分配。进程初始化时,CLR划出一个地址空间区域作为托管堆,CLR还要维护一个指针,我把它称作NextObjPtr。该指针指向下一个对象在堆中的分配位置。刚开始的时候,NextObjPtr设为地址空间区域的基本地址。
  一个区域被非垃圾对象填满后,CLR会分配更多的区域。这个过程一直重复,直至整个进程地址空间都被填满。所以,你的应用程序的内存受进程的虚拟地址空间的限制。32位进程最多能分配1.5GB,64位进程最多能分配8TB。

 C#的new操作符导致CLR执行以下步骤。
 1.计算类型的字段(以及从基类型继承的字段)所需的字节数。
 2.加上对象的开销所需的字节数。每个对象都有两个开销字段:类型对象指针和同步块索引。对于32位应用程序,这两个字段各自需要32位,所以每个对象都要8字节。对于64位应用程序,这两个字段各自需要64位,所以每个对象要增加16个字节。
 3.CLR检查区域中是否有分配对象所需的字节数。如果托管堆有足够的可用空间,就在NEXTOBJPTR指针指向的地址处放入对象,为对象分配的字节会被清零。接着调用类型的构造器,NEW操作符返回对象引用。就在返回这个引用之前,NEXToBJpTtr指针的值会加上对象战胜的字节数来得到一个新值,即下个对象放入托管堆时的地址。

垃圾回收算法

    应用程序调用new操作符创建对象时,可能没有足够地址空间来分配该对象,发现空间不够,CLR就执行垃圾回收。
    至于对象生存期的管理,有的系统采用的是某种引用计数算法。Microsoft自己的“组件对象模型”用的就是引用计算。在这种系统中,堆上的每个对象都维护着一个内存字段来统计程序中多少“部分”正在使用对象。随着每一“部分”到达代码中某个不再需要对象的地方,就递减对象的计算字段。计数字段成0,对象就可以从内存中删除了。许多引用计数系统最大的问题是处理不好循环引用。
    鉴于引用计数垃圾回收器算法存在的问题,CLR改为使用一种引用跟踪算法。引用跟踪算法中关心引用类型的变量,因为只有这种变量才能引用堆上的对象;值类型变量直接包含值类型实例。引用类型变量可在许多场合使用,包括静态和实例字段,或者方法的参数和局部变量。我们将所有引用类型的变量都称为根。
  CLR开始GC时,首先暂停进程中的所有线程。这样可以防止线程在CLR检查期间访问对象并更改其状态。然后,CLR进入GC的标记阶段。在这个阶段,CLR遍历堆中的所有对象,将同步块索引字段中的一位设为0。这表明所有对象都应删除。然后,CLR检查所有的活动根,查看它们引用了哪些对象。这正是CLR的GC称为引用跟踪GC的原因。如果一个根包含NULL,CLR忽略这个根并继续检查下一个根。
    任何根如果引用了堆上的对象,CLR都会标记那个对象,也就是将该对象的同步块索引中的位设为1。检查完毕后,堆中的对象要么已标记,要么未标记。已标记的对象不能被垃圾回收,因为至少有一个根在引用它。我们说这种对象是可达的。因为应用程序代码可通过仍在引用它的变量抵达(访问)它。未标记的对象是不可达的。因为应用程序中不存在使对象能被再次访问的根。
    CLR知道哪些对象可以幸存,哪些可以删除后,就进入GC的压缩阶段。在这个阶段。CLR对堆中标记的对象进行“乾坤大挪移”,压缩所有幸存下来的对象,使它们占连续的内存空间。这样做有许多好处。首先,所有幸存对象在内在中紧掺在一起,恢复了引用的“局部化”,减小了应用程序的工作集,从而提升了将来访问这些对象时的性能。
  如果CLR在一次GC之后回收不了内存,而且进程中没有空间来分配新的GC区域,就说明进程的内存已耗尽。此时,试图分配更多内存的new操作符会抛出出异常

垃圾回收和调试

  一旦根离开作用域,它引用的对象就会变得“不可达”,GC会回收其内存;不保存对象在方法的生存期中自始自终的存活。

  static void Main(string[] args)
        {
            Timer t = new Timer(TimerCallBack,null,0,2000);
            Console.ReadLine();
        }
        private static void TimerCallBack(object o)
        {
            Console.WriteLine("In timeCallback:" + DateTime.Now);
            GC.Collect();
        }
        观察代码,可能以为TimerCallBack方法每隔2000毫秒调用一次,毕竟,代码创建了一个Timer对象,而且有一个变量T引用该对象。只要计时器对象存在,计时器就应该一直触发。但要注意,TimerCallBack方法调用GC.Collect()强制执行了一次垃圾回收。
   回收开始时,垃圾回收器首先假定堆中所有的对象都是不可达的(垃圾);这自然也包括Timer对象。然后,垃圾回收器检查应用程序的根,发现在初始化后,Main方法再也没有用过变量t。既然应用程序没有任何变量引用timer对象,垃圾回收自然会回收分配给它的内存,这使计时器停止触发,并解释了为什么TimerCallBack方法只被调用了一次。
   使用C#编译器的/debug开关编译程序集时,编译器会应用System.Diagnostics.DebuggableAttribute,并为结果程序集设置DebuggingModes的DisableOptiimizations标志。运行时编译方法时,JIT编译器看到这个标志,会将所有根的生存期延长至方法结束。在我的例子中,JIt编译器认为Main的T变量必须存活至方法结束,所以在垃圾回收时,GC认为T仍然是一个根,t引用的对象仍然“可达”。Timer对象会在回收中存活,TimerCallBack方法会被反复调用,甚至Console.ReadLine方法返回而且Main方法退出。

 垃圾回收触发条件

       前面说过,CLR在检测第0代超过预算时触发一次GC。这是GC最常见的触发条件,下面列出其他条件。
       1.代码显示调用System.GC的静态Collect方法
代码可显示请求CLR执行回收。虽然Microsoft强烈反对这种请求,但有时情势比人强。
       2.Windows报告低内存情况
CLR 内部WIN32函数CreateMemoryResourceNotification和QueryMemoryResourceNotification监视系统的总体内存使用情况。如果Windows报告低内存,CLR将强制垃圾回收以释放死对象,减小进程工作集。
       3.CLR正在卸载AppDomain
一个AppDomain卸载时,ClR认为其中一切都不是根,所以执行函盖所有代的垃圾回收。
       4.CLR正在关闭
CLR 在进程正常终止时关闭。关闭期间,CLR认为进程中一切都不是根。对象有机会进行资源清理,但CLR不会试图压缩或释放内存。整个进程都要终止了,Winodws将回收进程的全部内存。

 垃圾回收模式 

       1.工作站
        该模式针对客户端应用程序优化GC。GC造成的延时很低,应用程序线程挂起时间会很短,避免使用户感到焦虑。在该模式中,GC假定机器运行的其他应用程序都不会消耗太多的CPU资源。

      2.服务器
       该模式针对服务器端应用程序优化GC。被优化的主要是吞叶量和资源利用。GC假定机器上没有运行其他应用程序,并假定机器的所有CPU都可用来辅助完成GC。该模式造成托管堆被拆分成几个区域,每个CPU一个。开始垃圾回收时,垃圾回收器在每个CPU上都运行一个特殊线程;每个线程都和其他线程并发回收它自己的区域。对于工作者线程行为一致的服务器应用程序,并发回收能很好地进行。这个功能要求应用程序在多CPU计算机上运行,使线程能真正地同时工作,从而获得性能的提升。

     
 







内容概要:本文深入探讨了Kotlin语言在函数式编程跨平台开发方面的特性优势,结合详细的代码案例,展示了Kotlin的核心技巧应用场景。文章首先介绍了高阶函数Lambda表达式的使用,解释了它们如何简化集合操作回调函数处理。接着,详细讲解了Kotlin Multiplatform(KMP)的实现方式,包括共享模块的创建平台特定模块的配置,展示了如何通过共享业务逻辑代码提高开发效率。最后,文章总结了Kotlin在Android开发、跨平台移动开发、后端开发Web开发中的应用场景,并展望了其未来发展趋势,指出Kotlin将继续在函数式编程跨平台开发领域不断完善发展。; 适合人群:对函数式编程跨平台开发感兴趣的开发者,尤其是有一定编程基础的Kotlin初学者中级开发者。; 使用场景及目标:①理解Kotlin中高阶函数Lambda表达式的使用方法及其在实际开发中的应用场景;②掌握Kotlin Multiplatform的实现方式,能够在多个平台上共享业务逻辑代码,提高开发效率;③了解Kotlin在不同开发领域的应用场景,为选择合适的技术栈提供参考。; 其他说明:本文不仅提供了理论知识,还结合了大量代码案例,帮助读者更好地理解实践Kotlin的函数式编程特性跨平台开发能力。建议读者在学习过程中动手实践代码案例,以加深理解掌握。
内容概要:本文深入探讨了利用历史速度命令(HVC)增强仿射编队机动控制性能的方法。论文提出了HVC在仿射编队控制中的潜在价值,通过全面评估HVC对系统的影响,提出了易于测试的稳定性条件,并给出了延迟参数与跟踪误差关系的显式不等式。研究为两轮差动机器人(TWDRs)群提供了系统的协调编队机动控制方案,并通过9台TWDRs的仿真实验验证了稳定性综合性能改进。此外,文中还提供了详细的Python代码实现,涵盖仿射编队控制类、HVC增强、稳定性条件检查以及仿真实验。代码不仅实现了论文的核心思想,还扩展了邻居历史信息利用、动态拓扑优化自适应控制等性能提升策略,更全面地反映了群体智能协作性能优化思想。 适用人群:具备一定编程基础,对群体智能、机器人编队控制、时滞系统稳定性分析感兴趣的科研人员工程师。 使用场景及目标:①理解HVC在仿射编队控制中的应用及其对系统性能的提升;②掌握仿射编队控制的具体实现方法,包括控制器设计、稳定性分析仿真实验;③学习如何通过引入历史信息(如HVC)来优化群体智能系统的性能;④探索中性型时滞系统的稳定性条件及其在实际系统中的应用。 其他说明:此资源不仅提供了理论分析,还包括完整的Python代码实现,帮助读者从理论到实践全面掌握仿射编队控制技术。代码结构清晰,涵盖了从初始化配置、控制律设计到性能评估的各个环节,并提供了丰富的可视化工具,便于理解分析系统性能。通过阅读实践,读者可以深入了解HVC增强仿射编队控制的工作原理及其实际应用效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值