垃圾收集器(.net / java)是实时系统的问题吗?

在构建需要非常一致且快速响应的系统时,垃圾收集器是否存在潜在问题?

我记得多年前的恐怖故事,其中典型的例子总是一个动作游戏,你的角色会在跳跃中停留几秒钟,当垃圾收集器进行清理时。

我们还需要几年时间,但我想知道这是否还是个问题。 我读到了.Net 4中的新垃圾收集器,但它看起来仍然像一个大黑盒子,你只需要相信一切都会好的。

如果你有一个总是必须快速响应的系统,有一个垃圾收集器太大问题,选择更硬核更好,控制它自己像c ++这样的语言? 我讨厌它,如果事实certificate是一个问题,除了等待新版本的运行时或做一些非常奇怪的事情试图影响收集器之外,基本上几乎没有什么可以做的。

编辑

感谢所有的宝贵资源。 但是,似乎大多数文章/自定义gc /解决方案都与Java环境有关。 .Net是否还具有自定义GC的调整function或选项?

确切地说,垃圾收集器是实时系统的问题。 更准确地说,可以用具有自动内存管理的语言编写实时软件。

有关使用Java实现实时行为的方法之一,可以在Java实时规范中找到更多详细信息。 RTSJ背后的想法非常简单 – 不要使用堆。 RTSJ提供了新的Runnable对象,确保线程不会访问任何类型的堆内存。 线程可以访问作用域内存(此处没有exception;当作用域关闭时值被销毁)或永久内存(在整个应用程序生命周期中都存在)。 永生记忆中的变量用新值一次又一次地写出来。

通过使用永久内存,RTSJ确保线程不访问堆,更重要的是,系统没有垃圾收集器,它先于线程执行程序。

更多细节可以在JPL和Sun出版的“Project Golden Gate:迈向太空任务中的实时Java”一文中找到 。

我用Java和.NET编写游戏,但从未发现这是一个大问题。 我希望你的“恐怖故事”基于多年前的垃圾收集器 – 从那时起,这项技术确实已经走了很长一段路。

我唯一不愿意在垃圾收集的基础上使用Java / .NET就像嵌入式编程一样具有硬实时约束(例如运动控制器)。

但是,您确实需要了解GC暂停,并且以下所有内容都有助于最大限度地降低GC暂停的风险:

  • 最大限度地减少新的对象分配 – 虽然现代GC系统中的对象分配速度非常快,但它们确实会对未来的暂停做出贡献,因此应尽量减少。 您可以使用预分配对象数组,保留对象池或使用未装箱的基元等技术。
  • 使用专门的低延迟库(如Javalution)来处理频繁使用的函数和数据类型。 这些专为实时/低延迟应用而设计
  • 当有多个版本可用时,请确保使用最佳GC算法。 我听说过Sun G1 Collector的低延迟应用程序。 最好的GC系统同时完成大部分收集,因此垃圾收集不必长时间“停止世界”。
  • 适当调整GC参数。 通常在整体性能和暂停时间之间进行权衡,您可能希望以牺牲前者为代价来改进后者。

如果您非常富有,您当然可以购买具有硬件GC支持的机器。 🙂

是的,必须在实时系统中以确定的方式处理垃圾。

一种方法是在每次存储器分配期间安排一定量的垃圾收集时间。 这称为“基于工作的垃圾收集”。 这个想法是,在没有泄漏的情况下,分配和收集应该是成比例的。

另一种简单的方法(“基于时间的垃圾收集”)是为了定期垃圾收集安排一定比例的时间,无论是否需要。

在任何一种情况下,程序都可能耗尽可用内存,因为不允许花费足够的时间来进行完整的垃圾收集。 这与非实时系统形成对比,非实时系统只要需要就可以暂停,以便收集垃圾。

从理论的角度来看,垃圾收集器不是问题,而是解决方案 。 当存在动态内存分配时,实时系统很难。 特别是,通常的C函数malloc()free()不提供实时保证(它们通常很快但至少在理论上具有使用过多时间的“最坏情况”)。

碰巧可以构建一个提供实时保证的动态内存分配器,但这需要分配器做一些繁重的事情,特别是在RAM中移动一些对象。 对象移动意味着调整指针(透明地,从应用​​程序代码的角度来看),此时分配器距离垃圾收集器只有一小步。

在保证响应时间的意义上,通常的Java或.NET实现不提供实时垃圾收集,但它们的GC仍然经过大量优化,并且在大多数情况下响应时间非常短。 在正常情况下,非常短的平均响应时间优于保证响应时间(“保证”并不意味着“快速”)。

另外,请注意,通常的Java或.NET实现也在非实时的操作系统上运行(操作系统可以决定安排其他线程,或者可能积极地将某些数据发送到交换文件,等等),也不是底层硬件(例如典型的硬盘可能会不时地“重新校准暂停”)。 如果您准备好容忍由于硬件导致的偶然的时序故障,那么您应该可以使用(经过精心调整的)JVM垃圾收集器。 即使是游戏。

这是一个潜在的问题,但……

当操作系统从过载的硬盘中检索一页内存时,你的角色也可能在C ++程序中间冻结。 如果您没有在设计用于提供具体性能保证的硬件上使用实时操作系统,则无法保证性能。

要获得更具体的答案,您必须询问特定虚拟机的特定实现。 如果垃圾收集虚拟机提供有关垃圾收集的适当性能保证,则可以将垃圾收集虚拟机用于实时系统。

你敢打赌这是一个问题。 如果您正在编写低延迟应用程序,则无法承受大多数垃圾收集器施加的停止世界停顿。 由于Java不允许您关闭GC,因此您唯一的选择是不产生垃圾。 这可以通过对象池和引导来完成。 我写了一篇博客文章 ,详细讨论了这个问题。

我们公司正在使用一个基于.Net的大型软件应用程序,该应用程序通过现场总线网络监控二进制传感器。 在某些情况下,传感器仅在短时间内激活(300 ms),但我们的软件仍然需要捕获这些事件,因为受控系统会在错过事件时立即失败。 我们最近发现,由于垃圾收集器长时间运行(最多1秒),我们的客户站点出现了问题。 我们仍在试图弄清楚如何对垃圾收集器实施时间限制。 总结这个简短的故事,我会说垃圾收集器是时间关键应用的障碍。