Search code examples
javamemorygarbage-collectionsoft-references

No garbage collector has time to collect SoftReference, always OutOfMemoryError


Tried all garbage collectors, a million different combinations of settings. But the result is always the same - OutOfMemoryError.

Can anyone tell which garbage collector will be able to timely remove objects referenced by soft references

Example emulator code below

package com;

import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.List;

class SoftReferenceCollector {

    private static class Data {
        public long[] l = new long[100];
    }

    private List<SoftReference<Data>> list = new ArrayList<>();

    public void startFillCollection(int durationInSec) {
        long i = 0;

        long start = System.currentTimeMillis();
        long end = start + durationInSec * 1000;
        while (System.currentTimeMillis() < end) {
            list.add(new SoftReference<>(new Data()));
            ++i;
            if (i % 10000 == 0) {
                sleep(1);
                if (i % 1_000_000 == 0)
                    sleep(1000);
            }
        }
    }

    private void sleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException ignored) {
        }
    }
}


public class Main6 {
    public static void main(String[] args) {
        SoftReferenceCollector softReferenceCollector = new SoftReferenceCollector();
        softReferenceCollector.startFillCollection(11240);

    }
}


Solution

  • Referents (Object referenced by the SoftReference) are being cleared by the GC before throwing an OOO Exception.

    But what is not being garbaged collected are the SoftReference objects themselves. They are objects too and they consume heap memory. They are all being held in memory by the list. GC only clears the object they point to, that is the referent.

    Run your JVM with -XX:+HeapDumpOnOutOfMemoryError. This flag will dump the heap before the OOO so you can later analyze it. You can use Eclipse Memory Analizer.

    You can also try -XX:+PrintReferenceGC flag which will print some informatión regarding time spent during gc cycle by cleaning those kind of references.