7

网上有一些文章提到了使用Stream-s 而不是旧的loop-s 的一些缺点:

但是从 GC 的角度来看有什么影响吗?正如我所假设的(正确吗?),每个流调用都会在下面创建一些短暂的对象。如果底层系统频繁调用使用流的特定代码片段,最终是否会从 GC 角度导致一些性能问题或给 GC 带来额外压力?还是影响很小,大部分时间都可以忽略?

有没有更详细的文章?

4

1 回答 1

3

公平地说,当霍尔格已经通过他的回答将主要思想联系起来时,给出一个答案是非常复杂的;我仍然会尝试。

GC 上的额外压力- 可能是。执行 GC 周期的额外时间 - 很可能不会。无视?我会说完全。最后,您关心的是GC- 回收大量空间需要很少的时间,最好是超级微小的世界末日事件。

让我们谈谈 GC 主要两个阶段的潜在开销:标记和疏散/重新分配(Shenandoah/ZGC)。第一mark阶段,GC找出什么是垃圾(通过实际识别什么是活着的)。

如果由 Stream 内部创建的对象不可访问,则它们将永远不会被扫描(这里为零开销),如果它们是可访问的,则扫描它们将非常快。故事的另一面是:当您创建一个对象并GC可能在它在标记阶段运行时触摸它,LoadBarrier 的慢速路径(在 的情况下Shenandoah)将处于活动状态。这将增加我假设的几十个ns特定阶段的总时间GC以及SATB队列中的一些空间。Aleksey Shipilev 在一次谈话中说,他试图测量执行单个障碍的开销,但无法测量,因此他测量3了时间在几十ns. 我不知道 ZGC 的确切细节,但也有一个 LoadBarrier。

要点是这个标记阶段是在应用程序运行时以并发方式完成的,因此您的应用程序仍然可以正常运行。并且即使某些 GC 代码会被触发来执行某些特定的工作(负载屏障),它也会非常快速并且对您完全透明。

第二阶段是“压缩”,或为未来分配腾出空间。ShenandoahGC 所做的是将活动对象从垃圾(肯定)最多的区域移动到空的区域。但只有活的物体。因此,如果某个区域有 100 个对象并且只有 1 个是活动的,那么只有 1 个会被移动,那么整个区域将被标记为空闲。因此,如果 Stream 实现仅生成垃圾(即:当前不存在),则可能是 GC 的“免费午餐”,它甚至不会知道它的存在。

这里更好的情况是这个阶段仍然是同时完成的。要保持“并发”处于活动状态,您需要知道从 GC 周期开始到结束分配了多少。此数量是您需要在 java 进程之上拥有的最小“额外”空间,以便让 GC 满意。

所以总的来说,你看到的是一个非常微小的影响;如果有的话。

于 2020-01-15T04:47:27.583 回答