1

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 -> {
    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."
Anton Ballmaier
  • 876
  • 9
  • 25
  • 2
    add `{` and `}` before declaration and after usage of `arr` – Iłya Bursov Aug 13 '20 at 14:24
  • It seems you can do with a triangular matrix `int index(int i, int j) = i(n+(n-i))/2 + j-i given j >= i` or such. Saving almost half the memory. – Joop Eggen Aug 13 '20 at 14:37
  • 1
    As a side note, do you know about [`Arrays.parallelSetAll(…)`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Arrays.html#parallelSetAll(T%5B%5D,java.util.function.IntFunction))? – Holger Aug 13 '20 at 16:39
  • Why do you care enough to null out the array? How big is it? – NomadMaker Aug 15 '20 at 18:29

3 Answers3

4

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.

Eugene
  • 117,005
  • 15
  • 201
  • 306
2

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.

Joni
  • 108,737
  • 14
  • 143
  • 193
-2

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

Mohammad
  • 187
  • 1
  • 12