在.NET中,您可以设置对象的GC生成,或者以其他方式指示它';它就要超出范围了?

在.NET中,您可以设置对象的GC生成,或者以其他方式指示它';它就要超出范围了?,.net,garbage-collection,.net,Garbage Collection,NET的垃圾收集器是一个分代垃圾收集器,基于大多数分配的对象都是短期的这一理念。因此,对象从“第0代”开始,在那里可以很容易地收集(通常是这样),而寿命较长的对象将升级到“第1代”和“第2代”,在那里它们会被更完整的扫描所触及。当一个方法将一个对象作为其状态的一部分进行分配,然后让该对象退出作用域时,通常会创建第0代对象 然而,有时那些将对象分配为状态的方法会运行很长时间。也许它们通过I/O调用阻塞,或者用一堆线程承载合并排序或数据库查询。在此期间发生的垃圾收集将在方法执行期间将这些状态对象提升

NET的垃圾收集器是一个分代垃圾收集器,基于大多数分配的对象都是短期的这一理念。因此,对象从“第0代”开始,在那里可以很容易地收集(通常是这样),而寿命较长的对象将升级到“第1代”和“第2代”,在那里它们会被更完整的扫描所触及。当一个方法将一个对象作为其状态的一部分进行分配,然后让该对象退出作用域时,通常会创建第0代对象

然而,有时那些将对象分配为状态的方法会运行很长时间。也许它们通过I/O调用阻塞,或者用一堆线程承载合并排序或数据库查询。在此期间发生的垃圾收集将在方法执行期间将这些状态对象提升到第1代和第2代。虽然这有助于将它们排除在快速垃圾收集清理之外,但一旦这个长期运行的方法结束,我就不再需要这些状态对象,也不再有被调用方持有对它们的任何引用

在这一点上,能够告诉垃圾收集器这一点是很好的。也就是说,是的,这个对象已经存在很长时间了,但是它很快就会被丢弃,垃圾收集器可以通过将对象移动到gen 0堆来响应。然后,下次需要执行垃圾收集时(例如下次调用此长时间运行的方法时),可以使用更快的第0代扫描而不是完全的阻塞扫描来回收必要的内存,从而减少垃圾收集器性能影响的不可预测性

其他一些信息:

  • 现在,我的团队将这些“本地状态”对象存储在巨大的可变结构中,通过
    ref
    中的
    参数传递,从而缓解了性能不可预测的问题。据我所知,.NET framework对于超出少量字节的任何结构(官方来源说16个,虽然我听说过24个)以及可变结构的优化效果都很差,但我不能否认这样一个事实,即这些结构具有自动作用域,并且在方法返回时肯定会被释放-当然,除非,我们可以向GC发出一个类即将退出的信号
  • 如果这是一个建议API,而不是命令,我会非常高兴,因为最终GC必须完成它必须完成的任务。也许,如果结果表明该对象在某个地方仍然有引用,那么最终将导致某种性能损失
  • 我也愿意回答有关垃圾收集框架(而非.NET)中存在的此功能的问题

    • 您的问题的简单答案是-不,没有这样的API。大多数现代地面军事系统的设计都考虑了“世代假设”,即大多数物体都会英年早逝或长寿。你所描述的通常被称为“中年危机”——生命足够长的物体可以被提升到最老的一代,但马上就不需要了。这显然远不是当前地面军事系统的最佳选择。避免这种情况的一种常见方法是:减少分配(提升的机会较小,因此我们经常停留在“年轻死亡”部分)或重用对象(因此我们进入“长寿”部分)

      通过大量重用结构和引用,您采用了第一种方法。您还可以考虑通过池重用对象,如
      ArrayPool
      或其他

      关于这些问题,您建议API用于:

      “垃圾收集器可以通过将对象移动到gen 0堆来响应”

      尽管它涉及到很多可能的实现细节,但很难想象它能被有效地实现。许多地面军事系统,包括.NET one,都尽力不复制/移动内存。代只是逻辑内存区域,边界前后移动。因此,“将对象移动到gen0”将需要复制它(可能需要复制所有保留的图形,使其变得合理),这将带来比潜在好处大得多的开销。更糟糕的是,目前这只能在GC期间完成,因为我们没有实现并发压缩(通常,在使用对象时移动对象)

      “据我所知,.NET framework对于任何超过少量字节的结构(官方来源说是16个,但我听说过24个)以及可变结构都没有进行很好的优化”


      这似乎有点虚假。NET运行时围绕结构的使用进行了大量优化,如果您通过
      ref
      传递它们,这是我能想到的最有效的方法之一。只需注意在
      参数中使用
      时可能会遇到的问题。

      NET和Java垃圾收集器的一个基本原则是,除非内存已从根本上损坏,否则永远无法观察到不标识活动对象的非空引用。如果.NET Framework或Java虚拟机包含一个函数,用于显式释放与GC管理的引用关联的对象,则它们必须确保在对象回收存储之前,对象的任何位置都不存在可观察的引用。由于这种保证的成本大约相当于一个垃圾收集周期,并且由于GC周期可以释放对象的存储空间,而不必给它一个引用,因此能够“手动”删除对象很少会增加太多价值。

      如果您通过ref传递它们,
      。。。。这是真的。但可悲的是,几乎没有人这样做。如果选择结构而不是类,通常是因为需要值语义。。。如果值足够小,可以合理地放入堆栈框架中,并且不需要比复制引用所需的工作量更多的工作,那么这种方法最为有效。@JoelCoehoorn如果要编写高性能的