【问题标题】:Java: Object pooling and hash setsJava:对象池和哈希集
【发布时间】:2019-09-29 21:09:36
【问题描述】:

让我们假设以下课程...

class Foo {

  private Bar1 bar1;
  private Bar2 bar2;

  // many other fields

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Foo foo = (Foo) o;
    if (!bar1.equals(foo.getBar1()) return false;
    if (!bar2.equals(foo.getBar2()) return false;
    // etc...
  }

  @Override
  public int hashCode() {
    int result = bar1.hashCode();
    result = 31 * result + bar2.hashCode();
    // etc...
  }

  // setters & getters follow...
}

每分钟创建、处理数千个 Foo 实例,然后在池中回收。工作流程如下:

Set<Foo> foos = new THashSet<>();
while (there-is-data) {

  String serializedDataFromApi = api.getData();
  Set<Foo> buffer = pool.deserializeAndCreate(serializedDataFromApi);
  foos.addAll(buffer);
}

processor.process(foos);
pool.recycle(foos);

问题是不同缓冲区之间可能存在重复的 foo 对象(具有相同的值)。这些被具体化为 Foo 的不同实例,但是在调用 foos.addAll(buffer) 时它们被认为是相等的。

我的问题是:

  • 那些“重复”实例发生了什么?
  • 它们是否“丢失”并被垃圾收集?
  • 如果我想将这些实例保留在池中,那么在插入之前使用 addAll 和回收实例测试重复项的最有效方法是什么?

【问题讨论】:

  • 只是好奇 - 为什么你需要所有这些?如果Foo 的实例是短暂的,那么这些实例不会留下年轻空间,因此会很快被收集。你的方法保证这些迟早会被转移到伊甸园空间。当您稍后重新使用这些并进行修改时,它会将整个区域标记为脏。我建议您对此池进行适当的测试。如果您编写(或编写)微基准测试,然后仔细检查它会测试您稍后将拥有的内容 - 对象位于伊甸园空间中并且不时修改。
  • 当您不想删除重复项时,只需使用List

标签: java garbage-collection duplicates set pooling


【解决方案1】:

这些“重复”实例发生了什么? 它们是否“丢失”并被收集垃圾?

是的,在 while (there-is-data) 的当前迭代完成后,这些将立即符合 GC 条件

如果我想将这些实例保留在池中,那么在插入之前使用 addAll 和回收实例测试重复项的最有效方法是什么?

Set.add 如果元素被插入则返回true,如果元素重复则返回false。所以你可以用

替换addAll
for (Foo f : buffer) {
  if (!foos.add(f)) {
    // handle duplicate
  }
}

不会对性能造成影响,因为addAll 的作用相同 - 迭代并一一添加。

【讨论】:

  • 谢谢亚历山大,这正是我想要的。但也非常感谢您对池测试的建议。我会这样做的。
猜你喜欢
  • 1970-01-01
  • 2016-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-06
  • 2017-10-03
  • 1970-01-01
相关资源
最近更新 更多