平衡分配
如果我们使用GCHeapCount配置来指定比核心更少的堆,这意味着只有那么多GC线程,并且默认情况下它们只能在那么多的内核上运行。当然,用户线程可以在其余核心上自由运行,它们所做的分配将平衡到GC堆上。
平衡GC工作
标记使用一个标记堆栈,这使得它成为工作偷窃的自然目标。当一个GC线程完成了自己的标记后,它会四处查看其他线程的标记堆栈是否仍在忙,如果仍然忙,则窃取一个对象进行标记。由于我们实现了“部分标记”,这意味着如果一个对象包含许多引用,我们一次只将其中的一块推送到标记堆栈上,而不会溢出堆栈。这意味着堆栈上的条目可能不是直接的对象地址。窃取需要识别特定的序列,以确定是否应该搜索其他条目,或者读取该序列中正确的条目进行窃取。请注意,这只在完全封锁地面军事系统期间开启,因为在某些情况下偷窃确实会造成明显的成本。
性能工作主要由用户场景驱动。随着我们的框架越来越多地被高性能场景使用,我们一直在努力缩短暂停时间。有人问过并行压缩GCs,是的,我们的路线图上确实有。但这并不意味着我们将停止改进我们目前的GC。我们在查看客户数据时注意到的一点是,当我们进行短暂的GC时,标记老一代对象所指向的年轻一代对象通常需要花费最长的时间。最近,我们在5.0中实现了工作窃取,通过让每个GC线程每次都要处理老一代的一大块。它以原子方式增加块索引,因此如果另一个线程也在查看同一代,那么它将获取下一个尚未获取的块。复杂的是我们可能有多个片段,所以我们需要跟踪当前正在处理的片段(及其起始索引)。当一个线程刚刚到达一个已经被其他线程处理过的段时,它知道要前进超过这个段。每个块保证只由一个线程处理。由于这一保证,而且将指针重新定位到年轻的gen对象共享相同的代码路径,这意味着重新定位工作也以同样的方式得到了平衡。
我们也在阶段结束时做平衡工作,这样就可以平衡在同一阶段发生的早期工作中的不平衡。
还有其他类型的平衡,但这些是最主要的。STW-GCs可以平衡更多的工作。我们选择更多地关注标记阶段,因为这是最需要的。我们没有平衡并发工作,仅仅是因为当你同时运行时它更容易被原谅。很明显,平衡这一点也是有好处的,所以这是一个去做的问题。