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