Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GC not clearing objects in scope

Tags:

java

java-8

jit

I had read an article long back and I dont seem to find it. It explained the below behavior where an object in scope might still not be cleared. In any case can you please help explain on why the below ends in OutOfMemoryError

public static void main(String[] args) {
    List<A> collect = null;
    int i=0;
    while(true){
        System.out.println(i++);
        collect = IntStream.range(0, 10_00_000).mapToObj(x -> new A(x + "")).collect(Collectors.toList());
    }
}

class A{
    String temp;
    A(String a){
        this.temp = a;
    }
}

When I put a finalize in A with a print statement, it is never printed. And the instance ends with OOME after few iterations. Why isn't gc clearing previously created collect. And the number of iterations as well is not constant, it ranges from 3 to even 100 but ultimately fails for -Xmx500m

Secondly for fun, I ran the above program with JIT disabled -Djava.compiler=NONE. And it runs forever as expected. How is JIT influencing it?

PS: When In include a System.gc(); inside my while clause, it keeps running as expected.

like image 255
Jatin Avatar asked Feb 07 '23 18:02

Jatin


1 Answers

I can’t reproduce your result with -Xmx500m, but with -Xmx200m. Consistently, the program will fail when you add the finalize() method, as the finalizer is the cause of the problem. However, there are some "finalized" message printed in my system. Without the finalize() method, it runs perfectly forever (well, actually until I kill it).

There is no problem reclaiming the space of ordinary objects, but when you add a nontrivial finalize() method, you are actively preventing the objects from going out of scope, as they now must be enqueued for finalization.

While the JVM will always perform a garbage collection, trying to free all unused objects, before throwing an OutOfMemoryError, there is no such guaranty for objects hanging in the finalization queue. Slowing down the main task by disabling the JIT may indeed allow the finalization to process more elements. Keep in mind that having both, the main task and the finalize method printing to System.out has a synchronization effect which can make the timing of the processing critical.

The are several environmental aspects that can influence the outcome. Since there is no guaranty regarding which thread will execute a finalizer, the finalization can use all unused CPU cores (and your main thread uses only one). Also the actual garbage collection algorithm (the JVM allows selecting one of several different algorithms) can have an impact.

like image 58
Holger Avatar answered Feb 22 '23 23:02

Holger