【问题标题】:Unusual Performance Setting Integer Array Values异常性能设置整数数组值
【发布时间】:2014-06-22 21:26:26
【问题描述】:

这是一个奇怪的案例,最近在分析我一直在研究的一个专业集合时出现。

该集合几乎只有两个数组,一个是 int[] 键数组,另一个是 Object[] 值数组,具有提供快速查找的哈希函数。这一切都很好,但我已经开始分析代码并且得到了一些奇怪的结果;对于分析,我决定用老式的方式来做,抓住System.currentTimeMillis(),一遍又一遍地运行测试,然后检查已经过去了多少时间,就像这样:

long sTime = System.currentTimeMillis();
for (int index : indices) 
    foo.remove(index);
long took = System.currentTimeMillis() - sTime;

在我的测试中,foo 准备了 200,000 个条目,并预先生成了 indices 列表,我将删除该列表。我使用循环重置并运行测试一千次,并将took 添加到运行总数中。

现在,对于命令,与其他数据类型相比,我得到了非常好的结果,除了我的remove(int) 方法。但是,我一直在努力找出原因,因为我的删除方法与我的 get(int) 方法相同(显然是删除除外),如图所示:

public Object get(int key) {
    int i = getIndex(key); // Hashes key and locates it
    return (i >= 0) ? this.values[i] : null;
}

public Object remove(int key) {
    int i = getIndex(key); // Does exactly the same as above
    if (i >= 0) {
        --this.size;
        ++this.modifications; // For concurrent access behaviour

        this.keys[i] = 0; // Zero indicates null entry
        Object old = this.values[i];
        this.values[i] = null;
        return old;
    }
    return null;
}

虽然我预计删除需要更长的时间,但它们的执行时间是 get(int) 的 5 倍以上。但是,如果我注释掉 this.keys[i] = 0 行,那么性能将与 get(int) 几乎相同。

我是否正确地观察到这是给我的int[] 数组赋值的问题?我尝试注释掉所有 this.values 操作并体验同样的缓慢时间,但是在注释掉 this.keys[i] = 0 的同时留下 this.values 始终可以解决问题;我完全不知道发生了什么事,有什么办法可以解决吗?

考虑到删除相对较少,性能仍然不错,但在 int[] 中设置值似乎会产生如此大的影响似乎很奇怪,所以我很想知道为什么。

【问题讨论】:

  • 我认为您需要提供一个完全可重现的基准,最好利用像 Caliper 这样的基准库来消除最常见的缺陷。
  • 随机猜测:当您将keys[] 元素归零时,getIndex() 在寻找密钥时还有更多工作要做。无论如何,请提供更多背景信息 - 问题可能出在您的基准测试中,也可能出在 getIndex() 或任何其他未显示给我们的地方。
  • 嗯,我希望避免发布太多内容;我的测试设置为仅对已知存在的键调用remove(int),并且getIndex(int) 在恒定时间内返回。此外,我确定不是 getIndex(int) 有问题,因为注释掉 this.keys[i] = 0 会显着改变结果(1200ms 到 200ms,与 get(int) 相同),我就是不明白为什么。
  • 我已经尝试创建一个 JBenchX 测试用例,并在使用和不使用 this.keys[i] = 0 的情况下运行了几次,并且得到了类似的结果。启用语句的测试大约需要 214ns,而没有启用语句的测试是 56ns。禁用this.keys[i] = 0 时,我将其替换为this.values[i] = DELETED(标记对象)和相应的检查,但不知何故它快了近四倍。
  • 查找读取keys[] 的代码片段。似乎归零会改变执行路径。尝试使用-Xint 选项运行JVM 以排除JIT 优化因素。 remove 还会慢 5 倍吗?

标签: java arrays performance


【解决方案1】:

编写的代码不能同时工作。如果没有显示其他并发代码,那很可能是源时序差异。除此之外,最可能的原因是除了 values[] 数组更改内存访问模式之外,仅访问 keys[] 数组。例如,从寄存器切换到内存位置,L1 缓存切换到 L2 缓存,或者 L3 缓存,或者主内存。 “虚假共享”是退化模式的一个例子。 “机械同理心”是用于调整当前硬件架构的名称。

【讨论】:

  • 它不是线程安全的类,modifications 变量用于从我的Iterator 抛出ConcurrentModificationException,以防发生并发访问。我不想费心把它留在代码 sn-p 中,但我觉得我应该这样做,以防它以某种方式成为问题的一部分。
  • 使用分析器。问题可能出在您尚未发布的部分代码中。
猜你喜欢
  • 1970-01-01
  • 2017-06-22
  • 1970-01-01
  • 1970-01-01
  • 2015-06-29
  • 1970-01-01
  • 2021-08-21
  • 2013-06-17
  • 1970-01-01
相关资源
最近更新 更多