通过确定性,我隐约意味着可以用于航空航天飞行软件等关键实时软件.垃圾收集器(以及动态内存分配)在飞行软件中是很大的禁忌,因为它们被认为是非确定性的.但是,我知道正在对此进行研究,所以我想知道这个问题是否已经解决了.
我还在问题中包括任何垃圾收集算法,这些算法限制了它们的使用方式.
我知道我可能会为这个回复获得很多下注,但是如果你已经在尝试首先避免动态内存,因为你说它是禁止的,你为什么要使用GC呢?我永远不会在可预测的运行时速度是主要问题的实时系统中使用GC.我会尽可能地避免使用动态内存,因此有很多非常少的动态对象可供使用,然后我会手动处理极少数动态分配,因此我可以100%控制某些内容何时发布以及它在哪里释放.毕竟不仅GC不是确定性的,free()与malloc()一样具有确定性.没有人说free()调用必须将内存标记为空闲.它可能会尝试将自由存储块周围的较小空闲内存块与一个较大的空闲内存块组合在一起,这种行为不是确定性的,
在一个关键的实时系统中,你甚至可以用不同的实现替换系统标准malloc()/ free(),甚至可以编写自己的实现(它不像听起来那么难!我之前就是为了好玩而做的它最有确定性.对我来说,GC是一个简单方便的东西,它是让程序员远离专注于复杂的malloc()/ free()规划,而是让系统自动处理.它有助于快速进行软件开发,并节省调试工作查找和修复内存泄漏的时间.但就像我从未在操作系统内核中使用GC一样,我也决不会在关键的实时应用程序中使用它.
如果我需要更复杂的内存处理,我可能会编写自己的malloc()/ free(),它可以按照需要运行(并且最具确定性),并在其上面编写我自己的引用计数模型.引用计数仍然是手动内存管理,但比使用malloc()/ free()更舒服.它不是超快,但确定性(至少增加/减少ref计数器在速度上是确定的)除非你可能有循环引用,否则如果你在整个应用程序中遵循保留/释放策略,它将捕获所有死记忆.唯一不确定的部分是你不知道调用release是否只会减少ref计数器或真正释放对象(取决于引用计数是否为零),但你可以通过提供一个来延迟实际的释放函数说"releaseWithoutFreeing" ,它将ref计数器减少一个,但即使它达到零,它也不会释放()对象.你的malloc()/ free()实现可以有一个函数"findDeadObjects",它搜索保留计数器为零的所有对象,这些对象尚未被释放并释放它们(稍后,当你处于不那么关键时你的代码的一部分,有更多的时间来完成这类任务).由于这也不是确定性的,你可以限制它可以用于"findDeadObjectsForUpTo(ms)"的时间量,ms是它可以用来查找和释放它们的毫秒数,这一次就会回来量子已被使用,所以你不会在这项任务上花费太多时间.你的malloc()/ free()实现可以有一个函数"findDeadObjects",它搜索保留计数器为零的所有对象,这些对象尚未被释放并释放它们(稍后,当你处于不那么关键时你的代码的一部分,有更多的时间来完成这类任务).由于这也不是确定性的,你可以限制它可以用于"findDeadObjectsForUpTo(ms)"的时间量,ms是它可以用来查找和释放它们的毫秒数,这一次就会回来量子已被使用,所以你不会在这项任务上花费太多时间.你的malloc()/ free()实现可以有一个函数"findDeadObjects",它搜索保留计数器为零的所有对象,这些对象尚未被释放并释放它们(稍后,当你处于不那么关键时你的代码的一部分,有更多的时间来完成这类任务).由于这也不是确定性的,你可以限制它可以用于"findDeadObjectsForUpTo(ms)"的时间量,ms是它可以用来查找和释放它们的毫秒数,这一次就会回来量子已被使用,所以你不会在这项任务上花费太多时间.当你处于代码中不太重要的部分时,有更多的时间来完成这类任务).由于这也不是确定性的,你可以限制它可以用于"findDeadObjectsForUpTo(ms)"的时间量,ms是它可以用来查找和释放它们的毫秒数,这一次就会回来量子已被使用,所以你不会在这项任务上花费太多时间.当你处于代码中不太重要的部分时,有更多的时间来完成这类任务).由于这也不是确定性的,你可以限制它可以用于"findDeadObjectsForUpTo(ms)"的时间量,ms是它可以用来查找和释放它们的毫秒数,这一次就会回来量子已被使用,所以你不会在这项任务上花费太多时间.
Metronome GC和BEA JRockit是我所知道的两种确定性GC实现(两者都适用于Java).
碰巧正在搜索Stack Overflow并注意到这个相当古老的帖子.
Jon Anderson提到了JamaicaVM.由于这些帖子已经使用了4年多,我认为回应这里发布的一些信息非常重要.
我为aicas,JamaicaVM,JamaicaCAR和Veriflux的开发商和营销人员工作.
JamaicaVM确实有一个硬实时垃圾收集器.它完全是先发制人的.实时操作系统中所需的完全相同的行为.虽然抢占延迟取决于CPU速度,但假设在Ghz类处理器上垃圾收集器的抢占时间小于1微秒.有一个32位单一版本,每个进程地址空间最多支持3 GB内存.有一个32位多核版本,每个进程地址空间和多个内核支持3 GB内存.还有64位单核和多核版本,每个进程地址空间支持高达128 GB的内存.垃圾收集器的性能与内存大小无关.为了响应关于运行GC完全内存不足的响应之一,对于硬实时系统,您不会将程序设计为执行此操作.实际上,虽然您可以在这种情况下使用硬实时GC,但您必须考虑到应用程序可能无法接受的最坏情况执行时间.
相反,正确的方法是分析程序以获得最大内存分配,然后将硬实时垃圾收集器配置为在所有先前分配期间逐步释放块,以便所描述的特定方案永远不会发生.这称为线程分布式,工作节奏垃圾收集.
Siebert博士关于硬实时垃圾收集器的书描述了如何实现这一点,并提供了一个正式的证据,证明垃圾收集器将跟上应用程序,同时不会成为O(N)操作.
了解实时垃圾收集意味着以下几点非常重要:
垃圾收集器是可抢占的,就像任何其他操作系统服务一样
在数学上可以证明垃圾收集器会跟上,这样内存就不会耗尽因为某些内存还没有被回收.
垃圾收集器不会分段内存,因此只要有可用内存,内存请求就会成功.
此外,您需要将其作为具有优先级反转保护,固定优先级线程调度程序和其他功能的系统的一部分.有关此信息,请参阅RTSJ.
虽然安全关键型应用程序需要进行硬实时垃圾收集,但它也可用于关键任务和通用Java应用程序.使用硬实时垃圾收集器没有固有的限制.对于一般用途,您可以期望更顺畅的程序执行,因为没有长的垃圾收集器暂停.