【发布时间】:2010-07-18 08:56:56
【问题描述】:
我自己和另一位开发人员最近从工作中的 Core 2 Duo 机器转移到了新的 Core 2 Quad 9505;都运行带有 JDK 1.6.0_18 的 Windows XP SP3 32 位。
这样做后,我们对一些计时/统计/指标聚合代码的一些自动化单元测试立即开始失败,因为 System.nanoTime() 返回的值似乎很荒谬。
在我的机器上可靠地显示这种行为的测试代码是:
import static org.junit.Assert.assertThat;
import org.hamcrest.Matchers;
import org.junit.Test;
public class NanoTest {
@Test
public void testNanoTime() throws InterruptedException {
final long sleepMillis = 5000;
long nanosBefore = System.nanoTime();
long millisBefore = System.currentTimeMillis();
Thread.sleep(sleepMillis);
long nanosTaken = System.nanoTime() - nanosBefore;
long millisTaken = System.currentTimeMillis() - millisBefore;
System.out.println("nanosTaken="+nanosTaken);
System.out.println("millisTaken="+millisTaken);
// Check it slept within 10% of requested time
assertThat((double)millisTaken, Matchers.closeTo(sleepMillis, sleepMillis * 0.1));
assertThat((double)nanosTaken, Matchers.closeTo(sleepMillis * 1000000, sleepMillis * 1000000 * 0.1));
}
}
典型输出:
millisTaken=5001
nanosTaken=2243785148
运行 100 倍会产生实际睡眠时间的 33% 到 60% 之间的纳米结果;不过通常在 40% 左右。
我了解 Windows 中计时器准确性方面的弱点,并阅读过像 Is System.nanoTime() consistent across threads? 这样的相关主题,但我的理解是 System.nanoTime() 正是为了我们使用它的目的而设计的:- 测量经过的时间;比 currentTimeMillis() 更准确。
有谁知道为什么它会返回如此疯狂的结果?这可能是硬件架构问题(唯一改变的主要是这台机器上的 CPU/主板)?我当前的硬件存在 Windows HAL 问题? JDK问题?我应该放弃 nanoTime() 吗?我应该在某处记录错误,还是对如何进一步调查有任何建议?
更新 19/07 03:15 UTC:在尝试了下面 finnw 的测试用例之后,我又进行了一些谷歌搜索,遇到了诸如 bugid:6440250 之类的条目。这也让我想起了周五晚些时候我注意到的其他一些奇怪的行为,其中 ping 恢复为负数。所以我将 /usepmtimer 添加到我的 boot.ini 中,现在所有测试都按预期运行。我的 ping 也正常。
我有点困惑为什么这仍然是一个问题;根据我的阅读,我认为 TSC 与 PMT 的问题在 Windows XP SP3 中得到了很大的解决。可能是因为我的机器原本是 SP2 的,并且被修补到 SP3 而不是最初安装为 SP3 吗?我现在也想知道我是否应该安装像MS KB896256 这样的补丁。也许我应该与公司桌面构建团队一起讨论这个问题?
【问题讨论】:
-
您是买了一台全新的机器还是升级了当前的机器以保留旧的 Windows 安装?
-
全新机器;在企业标准构建的基础上重建。
-
在 Windows 7 64 位最新 JDK 6 下工作正常。
-
如果有人在 2019 年或之后遇到此问题:这在自 OpenJDK 8u25 或 2019 年 2 月之前发布的任何版本以来的任何操作系统上都不是问题,模数未知的错误可能仍隐藏在某处.见 bugs.openjdk.java.net/browse/JDK-8045438