需要的内存空间取决于你程序中的分配速率。如果你的分配速率很高,GC在工作时需要更多的空间来实现增长。
另一个因素是对象的生命周期。如果你的对象通常存在非常短的生命周期,则可以通过使用分代收集器来管理略少一些的空间。
有很多研究论文可能会引起您的兴趣。稍后我会编辑一下以添加参考文献。
编辑(2011年1月):
我想到了一篇特定的论文,但现在似乎找不到了。以下这些论文很有意思,并包含一些相关的性能数据。作为经验法则,通常情况下,可用内存应该是程序驻留内存的两倍左右。有些程序需要更多,但其他程序即使在受限的环境中也可以表现得非常好。有很多变量会影响这一点,但分配速率是最重要的。
Immix: a mark-region garbage collector with space efficiency, fast collection, and mutator performance
Myths and realities: the performance impact of garbage collection
编辑(2013年2月):这个编辑在一篇引用文章的平衡观点和Tim Cooper提出的异议上进行了回应。
Quantifying the Performance of Garbage Collection vs. Explicit Memory Management,正如Natan Yellin所指出的,实际上是我最初在2011年1月时试图想起的参考文献。然而,我认为Natan提供的解释是不正确的。该研究并没有将GC与传统手动内存管理进行比较。相反,它将GC与一个可以执行完美显式释放的oracle进行比较。换句话说,它让我们无法知道传统手动内存管理与神奇的oracle相比表现如何。这也很难弄清楚,因为源程序要么是针对GC编写的,要么是针对手动内存管理编写的。因此,任何基准测试都具有固有的偏见。
在Tim Cooper的异议之后,我想澄清一下我对内存空间问题的立场。我主要是为了记录,因为我认为Stack Overflow的回答应该成为许多人长期使用的资源。
在典型的GC系统中有许多内存区域,但有三种抽象的内存类型:
- 已分配空间(包含活动、死亡和未跟踪对象)
- 保留空间(从中分配新对象)
- 工作区域(长期和短期GC数据结构)
什么是“headroom”?Headroom是维持期望性能所需的最小保留空间量。我认为这就是OP所问的。您还可以将headroom视为附加到实际程序驻留内存(最大活动内存)所需的内存,以实现良好的性能。
是的 - 增加headroom可以延迟垃圾收集并增加吞吐量。这对于离线非关键操作很重要。
实际上,大多数问题领域需要实时解决方案。有两种不同的实时性:
硬实时关注最坏情况下的延迟(对于关键任务系统) - 分配器的响应延迟是一种错误。
软实时关注平均或中位延迟 - 分配器的响应延迟是可以接受的,但不应经常发生。
大多数最先进的垃圾收集器针对软实时,这对于桌面应用程序以及按需提供服务的服务器都很好。如果将实时性作为要求取消,则可以使用停止-世界垃圾收集器,其中headroom开始失去意义。(注意:具有主要短期对象和高分配率的应用程序可能是一个例外,因为生存率较低。)
现在假设我们正在编写具有软实时要求的应用程序。为了简单起见,让我们假设GC在专用处理器上并发运行。假设程序具有以下人工属性:
平均驻留时间:1000 KB
保留headroom:100 KB
GC周期持续时间:1000 ms
和:
分配速率A:100 KB / s
分配速率B:200 KB / s
现在,我们可能会看到使用分配速率A的以下事件时间轴:
T + 0000 ms:GC周期开始,可用于分配的100 KB,已分配1000 KB
T + 1000 ms:
保留空间中没有免费空间,已分配1100 KB
GC周期结束,释放100 KB
预留空间中有100 KB空闲,已分配1000 KB
T + 2000 ms:与上述相同
使用分配速率B的事件时间轴不同。
- T+0000毫秒:GC循环开始,可用于分配的100KB,已经分配了1000KB
- T+0500毫秒:
- 保留空间中没有0KB可用,已分配1100KB
- 要么
- 延迟到GC循环结束(不好,但有时是必须的),或者
- 将保留大小增加到200KB,并保留100KB的空闲空间(在此假设)
- T+1000毫秒:
- 保留空间中没有0KB可用,已分配1200KB
- GC循环结束,释放200KB
- 保留空间中有200KB空闲,已分配1000KB
- T+2000毫秒:
- 保留空间中没有0KB可用,已分配1200KB
- GC循环结束,释放200KB
- 保留空间中有200KB空闲,已分配1000KB
请注意,分配速率直接影响所需的头部空间大小。使用分配速率B,我们需要两倍的头部空间来防止暂停并保持相同的性能水平。
这只是一个非常简化的例子,旨在说明一个想法。还有很多其他因素,但它确实展示了所期望的内容。请记住我提到的另一个主要因素:平均对象寿命。短寿命导致低存活率,与分配速率一起影响维持给定性能水平所需的内存量。
简而言之,在不知道和理解应用程序特性的情况下,不能对所需的头部空间做出一般性的声明。