Comment on JDK-826722: SoftReference not cleared on OutOfMemoryError: Requested array size exceeds VM limit

Raffaello Giulietti raffaello.giulietti at gmail.com
Fri Jun 4 20:24:33 UTC 2021


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
> 


More information about the core-libs-dev mailing list