Hi Mandy,

the OOME thrown for VM limits reasons is not related to any purported heap exhaustion but to the VM refusing to allocate an array of size Integer.MAX_VALUE or Integer.MAX_VALUE - 1, *even* if there's plenty of space.

For example, with 8 GiB of heap and a size of Integer.MAX_VALUE - 2 the small program runs without fuss:

    java -XX:+UseG1GC -Xms8g -Xmx8g -cp ... Softly 2147483645


But when the argument is increased by 1 to Integer.MAX_VALUE - 1

    java -XX:+UseG1GC -Xms8g -Xmx8g -cp ... Softly 2147483646

you immediately get:

Exception in thread "main" java.lang.AssertionError: non-null referent
        at Softly.main(Softly.java:26)
Caused by: java.lang.OutOfMemoryError: Requested array size exceeds VM limit
        at Softly.main(Softly.java:15)


In other words, OOME is "abused" in such cases. A VM limit error should really throw another kind of error, not OOME, because contrary to its name there's not necessarily a lack of memory space, as shown here.


To parallel current behavior, thus, the spec should be amended as proposed "... an OutOfMemoryError caused by Java heap space exhaustion." or a similar wording. Alternatively, to maintain the current spec untouched, the VM should throw another kind of error for VM limits. Not sure if this has any adverse impact on existing code in the wild.


Greetings
Raffaello




On 2021-06-04 21:16, Mandy Chung wrote:
I'm not sure if the spec should be updated.  JDK-8267222 needs the GC team to evaluate.

I have added my comment in this JBS issue.

The SoftReference spec has the guarantee:
   “All soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError.”

This is a reasonable guarantee expected by design in response to memory demand.

For the OOME thrown due to "requested array size exceeds VM limit", it seems that this is a fast-path throwing OOME without really going through the object allocation request (where reference processing will be performed in GC cycle).

The question to the GC team is whether VM implementation can and should support this soft reference guarantee. Note that the soft reference objects are cleared as specified, the large object allocation exceeding VM limit would fail any way. If the implementation is feasible, I'm inclined to clear the soft reference objects when OOME is thrown as specified even the object allocation request is known to fail.

Mandy

On 6/3/21 11:57 AM, Raffaello Giulietti wrote:
Hi,

upon reading [1] I tried a similar scenario, but where OOME are caused by "Java heap space" exhaustion rather than by VM limits.


import java.lang.ref.SoftReference;
import java.text.DecimalFormat;
import java.util.ArrayList;

public class Softly {

    public static void main(String[] args) {
        var size = Integer.parseInt(args[0]);
        var format = new DecimalFormat("#,###");
        var news = 0;
        var ref = new SoftReference<>(new ArrayList<>());
        for (;;) {
            byte[] b = null;
            try {
                b = new byte[size];
                ++news;
                ref.get().add(b);
            } catch (NullPointerException __) {
                System.out.format("totSize = %20s, allocations = %d\n", format.format((long) news * size), news);
                ref = new SoftReference<>(new ArrayList<>());
                ref.get().add(b);
            } catch (OutOfMemoryError e) {
                if (ref.refersTo(null)) {
                    throw new AssertionError("allocations = %d".formatted((news)), e);
                }
                throw new AssertionError("non-null referent", e);
            }
        }
    }

}


E.g.,
java -XX:+UseG1GC -Xms1g -Xmx1g -cp ... Softly 800000000


Depending on the collector and how tight the heap is, I sometimes observe a "Java heap space" OOME but then the referent of ref is null. I never observed a OOME with a non-null referent for ref. Hence, in scenarios where OOME are caused by heap exhaustion, soft refs seem to work as advertised.

Tried on AdoptOpenJDK-16.0.1+9 with SerialGC, ParallelGC, G1GC, ZGC and ShenandoahGC with either -Xms1g/-Xmx1g or -Xms2g/-Xmx2g (small heaps) and various byte[] sizes.

Thus, the current wording in SoftReference's javadoc:

"All soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError."

could be amended to read:

"All soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError caused by Java heap space exhaustion."


Greetings
Raffaello

----

[1] https://bugs.openjdk.java.net/browse/JDK-8267222

Reply via email to