本文转载自微信公众号“DotNET技术圈”,作者RICKYLEEKS。转载本文请联系DotNET技术圈公众号。1、小物件如何处理?小型.NET对象分配在小型对象堆(SOH)上。其中有3个:第0代、第1代和第2代。对象根据其生命周期向上移动。将新对象放在Gen0上。当Gen0已满时,.NET垃圾收集器(GC)运行,处理不再需要的对象,并将其他所有对象移至Gen1。如果Gen1已满,GC将再次运行,并且还可以将对象从Gen1移动到Gen2。当Gen2变满时,将发生GCfull运行。这将清除不需要的Gen2对象,将Gen1对象移动到Gen2,然后将Gen0对象移动到Gen1,最后清除所有未引用的内容。每次GC运行后,受影响的堆都会被压缩,以保持内存仍在一起使用。这种分代方法使事情高效运行-耗时的压缩过程仅在绝对必要时才会发生。注意:如果在Gen2中看到大量内存,说明内存已经预留了很长时间,可能存在内存问题。这就是内存分析工具可以派上用场的地方。2.更大的物体会怎样?大于85KB的对象分配到大对象堆(LOH)。由于复制大块内存的开销,它们没有被压缩。当发生fullGC时,未使用的LOH对象的地址范围将被记录在空闲空间分配表中。当一个新的对象被分配时,这个空闲空间表会检查一个足够大的地址范围来容纳这个对象。如果存在,则将对象分配在那里,如果不存在,则将对象分配到下一个可用空间。由于对象不太可能是空地址范围的确切大小,因此几乎总是会在对象之间留下小块内存,从而导致碎片。如果块小于85KB,则根本没有重用的可能性。因此,随着分配需求的增加,即使片段空间仍然可用,也会保留新的片段。此外,当需要分配大对象时,.NET仍然倾向于将对象附加到末尾,而不是运行昂贵的Gen2GC。这对性能有好处,但是是造成内存碎片的重要原因3.垃圾收集器可以运行在不同的模式下以优化性能。NET通过为GC提供多种模式来解决性能和堆效率之间的权衡。工作站模式为用户提供最大的响应能力并减少因GC而导致的暂停。它可以作为“并发”或“非并发”运行,指的是运行GC的线程。默认是concurrent,即GC使用一个单独的线程,所以应用程序可以在GC运行的时候继续执行。服务器模式为服务器环境提供最大的吞吐量、可扩展性和性能。在服务器模式下,段大小和生成阈值通常比工作站模式大得多,反映出对服务器的更高要求。服务器模式在多个线程上并行运行垃圾收集,为每个逻辑处理器分配一个单独的SOH和LOH,以防止线程相互干扰。.NET框架提供了一种交叉引用机制,因此对象仍然可以跨堆相互引用。但是,由于应用程序响应不是服务器模式的直接目标,因此在GC期间所有应用程序线程都将被挂起。4.引用不足是性能和内存效率之间的权衡弱对象有备用的GC根引用源,允许您在GC需要时收集对象时保留对象。它们是代码性能和内存效率之间的折衷。创建一个对象需要CPU时间,但保持它加载需要内存。弱引用对于大型数据结构特别有用。例如,假设您有一个允许用户浏览大型数据结构的应用程序,他们可能会返回其中的一些数据。您可以将他们浏览的结构中的任何强引用转换为弱引用。如果用户返回这些结构,它们可以被使用,但如果没有,GC可以根据需要回收内存。5.对象固定可以创建在托管代码和非托管代码之间传递的引用。NET使用称为GCHandle的结构来跟踪堆对象。GCHandle可用于在托管域和非托管域之间传递对象引用,.NET为此维护了一个GCHandles表。GCHandle有四种类型,包括固定的,用于将对象固定在内存中的特定地址。对象固定的主要问题是它会导致SOH碎片。如果一个对象在GC期间被固定,则根据定义它不能被重定位。根据您使用固定的方式,它会降低压缩效率,在堆中留下间隙。避免这种情况的最佳策略是锁定一小段时间,然后释放。
