公平地说,当霍尔格已经通过他的回答将主要思想联系起来时,给出一个答案是非常复杂的;我仍然会尝试。
GC 上的额外压力- 可能是。执行 GC 周期的额外时间 - 很可能不会。无视?我会说完全。最后,您关心的是GC
- 回收大量空间需要很少的时间,最好是超级微小的世界末日事件。
让我们谈谈 GC 主要两个阶段的潜在开销:标记和疏散/重新分配(Shenandoah/ZGC)。第一mark
阶段,GC
找出什么是垃圾(通过实际识别什么是活着的)。
如果由 Stream 内部创建的对象不可访问,则它们将永远不会被扫描(这里为零开销),如果它们是可访问的,则扫描它们将非常快。故事的另一面是:当您创建一个对象并GC
可能在它在标记阶段运行时触摸它时,LoadBarrier 的慢速路径(在 的情况下Shenandoah
)将处于活动状态。这将增加我假设的几十个ns
特定阶段的总时间GC
以及SATB
队列中的一些空间。Aleksey Shipilev 在一次谈话中说,他试图测量执行单个障碍的开销,但无法测量,因此他测量3
了时间在几十ns
. 我不知道 ZGC 的确切细节,但也有一个 LoadBarrier。
要点是这个标记阶段是在应用程序运行时以并发方式完成的,因此您的应用程序仍然可以正常运行。并且即使某些 GC 代码会被触发来执行某些特定的工作(负载屏障),它也会非常快速并且对您完全透明。
第二阶段是“压缩”,或为未来分配腾出空间。Shenandoah
GC 所做的是将活动对象从垃圾(肯定)最多的区域移动到空的区域。但只有活的物体。因此,如果某个区域有 100 个对象并且只有 1 个是活动的,那么只有 1 个会被移动,那么整个区域将被标记为空闲。因此,如果 Stream 实现仅生成垃圾(即:当前不存在),则可能是 GC 的“免费午餐”,它甚至不会知道它的存在。
这里更好的情况是这个阶段仍然是同时完成的。要保持“并发”处于活动状态,您需要知道从 GC 周期开始到结束分配了多少。此数量是您需要在 java 进程之上拥有的最小“额外”空间,以便让 GC 满意。
所以总的来说,你看到的是一个非常微小的影响;如果有的话。