Java:重用vs重新分配对容器对象的引用?

Man*_*odi 1 java performance garbage-collection hashset time-complexity

tl; dr:在Java中,更好的是,每次重用容器对象或创建对象,让垃圾收集器完成工作

我正在处理Java中的大量数据,我经常使用以下类型的代码结构: -

版本1:

for(...){//outer loop
   HashSet<Integer> test = new HashSet<>(); //Some container
   for(...){
      //Inner loop working on the above container Data Structure
   }
   //More operation on the container defined above
}//Outer loop ends
Run Code Online (Sandbox Code Playgroud)

在这里,我每次在循环中分配新内存,并在再次分配空内存之前在内部/外部循环中执行一些操作.

现在我担心Java中的内存泄漏.我知道Java有一个相当不错的垃圾收集器,但我应该修改我的代码而不是依赖它,如下:

版本2:

HashSet<Integer> test = null;
for(...){//outer loop
   if(test == null){
      test = new HashSet<>(); //Some container
   }else{
      test.clear()
   }
   for(...){
      //Inner loop working on the above container Data Structure
   }
   //More operation on the container defined above
}//Outer loop ends
Run Code Online (Sandbox Code Playgroud)

我有三个问题: -

  1. 哪个会表现更好,或者没有明确的答案.
  2. 第二版会有更多的时间复杂性吗?换句话说,复杂性为O(n)的clear()函数O(1).我在javadocs中没有任何东西.
  3. 这个模式很常见,哪个版本更推荐一个?

Tag*_*eev 5

我认为最好使用第一种方法.请注意,HashSet.clear永远不要缩小哈希表的大小.因此,如果外部循环的第一次迭代向集合添加了许多元素,则散列表将变得非常大,但是在后续迭代中,即使不需要缩小也需要更少的空间.

第一个版本也使得进一步的重构变得更容易:您可能稍后想要将整个内部循环放入单独的方法中.使用第一个版本,你可以将它与它一起移动HashSet.

最后请注意,对于垃圾收集,通常更容易管理短期对象.如果您HashSet的寿命很长,则可能会将其移至旧代并仅在完整GC期间删除.