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

如何在Java中(有效地)删除最终数组,java,garbage-collection,final,Java,Garbage Collection,Final,我想删除对大型数组的引用,方法是在使用引用后对其进行nulling。然而,这给了我一个编译器错误,因为对数组的并行赋值要求数组是(有效的)最终的(至少我认为问题是…)。如何允许垃圾收集删除阵列 double[][] arr = new double[n][n]; IntStream.range(0, n).parallel().forEach(i -> { for(int j=0;j<i;j++) { directDistances[i][j] = direc

我想删除对大型数组的引用,方法是在使用引用后对其进行
null
ing。然而,这给了我一个编译器错误,因为对数组的并行赋值要求数组是(有效的)最终的(至少我认为问题是…)。如何允许垃圾收集删除阵列

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] = ...;
    }
});

//Use arr here...

arr = null; //arr no longer needed.
//This gives the error "Local variable defined in an enclosing scope must be final or effectively final."
double[]arr=新的双精度[n][n];
IntStream.range(0,n).parallel().forEach(i->{

对于(int j=0;j使用
AtomicReference ar=new AtomicReference();ar.set(arr);
这将为您提供有效的最终阵列
然后使用ar.set()和ar.get()方法修改数组

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

该数组最迟在该方法返回时才有资格进行垃圾收集-不需要将其设置为null

如果您有一个很长的方法,并且担心数组在剩下的部分会保留下来,那么解决方案是编写较小的方法。将功能划分为较小的方法也可以提高可读性和可重用性

如果您不能或不想编写较小的方法,在方法中引入单独的块可能会有所帮助。局部变量声明是块的局部声明,因此此“技巧”还允许您在方法中的不同块中重复使用变量名

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

从技术上讲,数组在最后一次使用之后,即变量超出作用域之前,就有资格进行垃圾收集。这是由以下人员明确允许的:

可以设计程序的优化转换,以减少可访问对象的数量,使其少于通常认为可访问的对象的数量。例如,Java编译器或代码生成器可以选择将不再使用的变量或参数设置为null,以使此类对象的存储空间为空有可能更快地回收

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

最晚当方法返回时,数组才有资格进行垃圾收集-您不需要不需要将其设置为null

如果您有一个很长的方法,并且担心数组在剩下的部分会保留下来,那么解决方案是编写较小的方法。将功能划分为较小的方法也可以提高可读性和可重用性

如果您不能或不想编写较小的方法,在方法中引入单独的块可能会有所帮助。局部变量声明是块的局部声明,因此此“技巧”还允许您在方法中的不同块中重复使用变量名

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

从技术上讲,数组在最后一次使用之后,即变量超出作用域之前,就有资格进行垃圾收集。这是由以下人员明确允许的:

可以设计程序的优化转换,以减少可访问对象的数量,使其少于通常认为可访问的对象的数量。例如,Java编译器或代码生成器可以选择将不再使用的变量或参数设置为null,以使此类对象的存储空间为空有可能更快地回收

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

我想删除对大型数组的引用,方法是在使用该引用后将其置零

不要

我所知道的JVM世界中的所有实现都会扫描线程堆栈以找出可访问的对象。这意味着该方法的范围与对象的生存时间无关。简单地说:

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

      // done
}
在第
//行停止使用字节数组
之后,
字节
符合垃圾收集的条件。在方法结束后,它将不符合垃圾收集的条件。该方法的范围(介于
{
}
之间的所有内容)不会影响
字节
的存活时间

我想删除对大型数组的引用,方法是在使用该引用后将其置零

不要

我所知道的JVM世界中的所有实现都会扫描线程堆栈以找出可访问的对象。这意味着该方法的范围与对象的生存时间无关。简单地说:

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

      // done
}

在第
//行停止使用字节数组
之后,
字节
符合垃圾收集的条件。在方法结束后,它将不符合垃圾收集的条件。该方法的范围(介于
{
}
之间的所有内容)不会影响
字节
的存活时间。

添加
{
}
在声明之前和使用
arr
之后,您似乎可以使用三角形矩阵
int index(int i,int j)=i(n+(n-i))/2+j-i给定j>=i
或诸如此类。节省了几乎一半的内存。作为旁注,您知道吗?为什么您非常关心清空数组?它有多大?添加
{
}
在声明之前和使用
arr
之后,似乎可以使用三角形矩阵
int索引(int i,int j)=i(n+(n-i))/2+j-i给定j>=i
或诸如此类。节省了几乎一半的内存。顺便说一句,你知道吗?你为什么要把数组调零?它有多大?你混淆了作用域和可达性,顺便说一句。你混淆了作用域和可达性,顺便说一句。