【问题标题】:Does FIXME: NYI in MutableCallSite.syncAll mean not yet implemented?MutableCallSite.syncAll 中的 FIXME: NYI 是否意味着尚未实现?
【发布时间】:2021-11-30 00:50:41
【问题描述】:

java.lang.invoke 中有两个有趣的结构,MutableCallSiteSwitchPoint。它们被描述为提供了一种更改目标的方法(对于MutableCallSite,可以更改为任意不同的目标,对于SwitchPoint,可以更改为预定义的无效时目标),其他线程保证可以获取更新,但使用在 MCS 或 SP 未更改时减少了使用 MCS 或 SP 的开销(与在每次使用时检查同步效果相比减少了)。 SwitchPoint 文档说它可以在 MutableCallSite 上构建,并且在 GitHub 上的 OpenJDK 源代码中,它是。所以寻找魔法的地方是MutableCallSite.syncAll

the source for that method中,魔法似乎分三步:

  • 第 1 步是 lazySetsetRelease 的 JMM 效果)在其他线程永远不会读取的私有 AtomicInteger 上;
  • 第 2 步查看所有传递的 MutableCallSite 引用以确认没有一个为空;
  • 第三步是评论:// FIXME: NYI

对于未经训练的人来说,该评论似乎还有很多工作要做。 ;)

Android 的开发人员似乎看到了该评论和 removed the method from Android,因为他们不想宣传未实现的方法(即使 MutableCallSite 没有 syncAll 看起来不像一个有用的结构)。他们说的对吗?

另一方面,它似乎真的不太可能如此明显地缺少它的功能。从 Java 7 开始,它就已经在 J​​ava 中了,而且像 Nashorn 和 JRuby 这样的重要项目已经大量使用了MutableCallSiteSwitchPoint。我没有偶然发现任何关于它们因此而被破坏的cmets。

此外,我了解 Java 类库中的某些实现可能看起来不完整,因为部分魔法是由 JVM 实现提供的。这似乎是一个可能发生的主要示例,但我无法找到详细信息。

有人知道细节吗?最好知道真正的可靠行为是什么。 syncAll javadoc 一开始听起来很有希望。释义:

  1. 其作用是强制每个呼叫站点目标的所有未来读者接受最近存储的值
  2. 它可能(可能??)阻塞,直到所有读者(以某种方式)解除所有先前版本的缓存
  3. 阅读器线程可能会观察目标的先前版本,直到syncAll 调用返回。 (这是否意味着他们syncAll 调用返回后可能不会这样做?如果是这样,那不是意味着#2 真的比“可能”更强大吗?)
  4. 它“可能很贵”(作为让 getTarget 便宜的权衡;这是神奇的部分)。

但稍后在同一个 javadoc 中,深入研究 JMM 细节,它说“如果(其他线程)T 在 volatile 写入之后执行同步操作 A”... 然后 它必须看到更新的目标。

这听起来有点……不那么健壮。

这是否全部基于一些 JVM 实现知识,即在 syncAll 返回后可以花费多长时间的上限?如果是,可以说明这个上限吗?

如果确实没有遗漏任何东西并且事情像宣传的那样工作,是否值得删除源中的// FIXME: NYI(也许用对实际情况的解释来替换它)?

欲了解更多信息:earlier version of this question 已发布在 mlvm-dev 列表中,但没有收到任何回复。

【问题讨论】:

标签: java android concurrency jvm


【解决方案1】:

boneill 的评论和 Remi Forax 的链接并发兴趣邮件列表响应似乎包含了答案。 MutableCallSite.syncAll 方法实际上并没有做宣传的事情,但行为最终是足够的,因为 MutableCallSite.setTarget 比宣传的更多。所以在方案中

for ( i = 0; i < sites.length; ++ i )
  sites[i].setTarget(newTargets[i]);
MutableCallSite.syncAll(sites);

发生必要的同步;只是大部分工作发生在syncAll 之前。同样,

SwitchPoint.invalidateAll(switchpoints);

(就像上面一样作为循环实现,触及每个SwitchPoint 底层的MutableCallSite)也会发生必要的工作。

不过,这个部分实现的方案并不完美:将繁重的工作从 syncAll 转移到 setTarget 似乎牺牲了更新后只需支付一次 syncAll 成本的广告利益n 调用站点目标。在这个实现中,该成本(mark_dependent_nmethodsdeoptimize_all_marked 通过与所有线程握手)发生 n 次,但每次只处理一个 CallSite 的依赖关系。同样对于 SwitchPoint.invalidateAll 具有 n SwitchPoints 的数组。

我不知道为什么它自 Java 7 以来一直处于这种开发状态,但如果它按照最初记录的方式实现,看起来可能会有很好的性能提升空间。

【讨论】:

    猜你喜欢
    • 2014-01-23
    • 2014-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-14
    • 2016-12-20
    • 2017-05-10
    • 2011-09-02
    相关资源
    最近更新 更多