如何在Java中删除一个(有效地)最终数组

huangapple go评论70阅读模式
英文:

How to delete an (effectively) final array in Java

问题

我想在使用数组后通过将引用设置为null来删除对大数组的引用。然而,这会导致编译器错误,因为对数组的并行赋值要求数组是(实际上)final的(至少我认为问题是这样的...)。如何允许垃圾回收删除数组?

double[][] arr = new double[n][n];
IntStream.range(0, n).parallel().forEach(i -> {
    for (int j = 0; j < i; j++) {
        directDistances[i][j] = directDistances[j][i] = ...;
    }
});

//在这里使用arr...

arr = null; //arr不再需要。
//这会导致错误:“在封闭范围中定义的局部变量必须是final或者实际上是final的。”
英文:

I want to delete remove the reference to a large array by nulling the reference after I used it. This gives me a compiler error however, since the parallel assignment to the array requires the array to be (effectivly) final (at least that is what I think the problem is...). How can I allow the garbage collection to remove the array?

double[][] arr = new double[n][n];
IntStream.range(0, n).parallel().forEach(i -&gt; {
	for(int j=0;j&lt;i;j++) {
		directDistances[i][j] = directDistances[j][i] = ...;
	}
});

//Use arr here...

arr = null; //arr no longer needed.
//This gives the error &quot;Local variable defined in an enclosing scope must be final or effectively final.&quot;

答案1

得分: 4

不要。

我所了解的JVM世界中的所有实现都会扫描线程堆栈以查找可达对象。这意味着方法的范围与对象保持活动状态的时间没有任何关系。简单来说:

void yourMethod(){
    
      byte [] bytes = ....
      // 使用字节数组
 
      // 停止使用字节数组
      // .... 10,000 行代码

      // 完成
}

// 停止使用字节数组之后,bytes在立即可进行垃圾回收。它不会在方法结束后才成为可回收对象。方法的范围(在{}之间的所有内容)不会影响bytes的存活时间。这里有一个证明的示例

英文:

> I want to delete remove the reference to a large array by nulling the reference after I used it

Don't.

All implementations that I am aware of in the JVM world, will scan thread stacks to find out reachable objects. This means that scope of the method has nothing to do with how long an Object is kept alive. In simpler words:

void yourMethod(){
    
      byte [] bytes = ....
      // use bytes array somehow
 
      // stop using the byte array
      // .... 10_000 lines of code

      // done
}

immediately after the line // stop using the byte array, bytes IS eligible for garbage collection. It is not going to be eligible after the method ends. scope of the method (everything between { and }) does not influence how much bytes is going to stay alive. here is an example that proves this.

答案2

得分: 2

数组最迟在方法返回时变为可垃圾回收 - 你不需要将其设置为null。

如果你有一个很长的方法,并且担心数组会一直存在于方法的其余部分,解决方法是编写较小的方法。将功能分成较小的方法也可以提高可读性和可重用性。

如果你不能或不想编写较小的方法,引入方法中的分离块可能有所帮助。局部变量声明仅在块内部有效,因此这种“技巧”还允许你在方法的不同块中重复使用变量名。

技术上,数组在最后一次使用后变为可垃圾回收,可以在方法中间 - 在变量超出范围之前。这是由语言规范中的第12.6.1节明确允许的

> 可以设计程序的优化转换,使得可达的对象的数量少于那些表面上可达的对象的数量。例如,Java编译器或代码生成器可以选择将将不再使用的变量或参数设置为null,以使该对象的存储可以更早地被回收。

虽然规范允许这种优化,但并不要求它。如果你发现在特定情况下没有进行这种优化,并且需要更好的保证,将大方法拆分成较小的方法将有所帮助。

英文:

The array becomes eligible for garbage collection at the latest when the method returns - you don't need to set it to null.

If you have a long method and are concerned that the array is kept around for the rest of it, the solution is to write smaller methods. Dividing the functionality among smaller methods may also improve readability and reusability.

If you can't or don't want to write smaller methods, introducing separate blocks in the method may help. Local variable declarations are local to the block, so this "trick" also lets you re-use a variable name in different blocks in the method.

void largeMethod() {
    first: {
        final int number = 1;
    }
    second: {
        final int number = 2;
    }
}

Technically, the array becomes eligible for garbage collection after its last use, which can be in the middle of the method - before the variable goes out of scope. This is explicitly allowed by section 12.6.1 in the language specification:

> Optimizing transformations of a program can be designed that reduce the number of objects that are reachable to be less than those which would naively be considered reachable. For example, a Java compiler or code generator may choose to set a variable or parameter that will no longer be used to null to cause the storage for such an object to be potentially reclaimable sooner.

While the specification allows this optimization, it does not require it. If you find that the optimization is not being made in a particular situation and you need a better guarantee, splitting the big method into smaller methods will help.

答案3

得分: -2

使用AtomicReference ar = new AtomicReference () ; ar. set(arr) ;
这将为您提供一个有效的最终数组
然后使用ar.set()和ar.get()方法来修改数组

英文:

Use AtomicReference ar = new AtomicReference () ;
ar. set(arr) ;

This will provide you with an effectively final array
Then use ar.set() and ar.get() methods to modify the array

huangapple
  • 本文由 发表于 2020年8月13日 22:21:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/63397221.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定