SoftReference incorrect javadoc?
Michael Pollmeier
michael at michaelpollmeier.com
Wed Apr 17 04:38:19 UTC 2019
You're right, without overriding `finalized` it does free softly
referenced objects. That's still a bug IMO in JRE <11, but more nuanced
than what I first assumed.
So we probably don't need to worry about it any further. Good to know
and have it documented here.
Many thanks
Michael
On 17/04/19 4:01 pm, Bernd Eckenfels wrote:
> Your test code does not fail because of the SoftRef but because of the
> Finalizer I think. But it’s good to know that 11 handles this better.
>
> --
> https://Bernd.eckenfels.net
>
> ------------------------------------------------------------------------
> *Von:* Michael Pollmeier <michael at michaelpollmeier.com>
> *Gesendet:* Mittwoch, April 17, 2019 5:54 AM
> *An:* jdk-dev at openjdk.java.net
> *Cc:* ecki at zusammenkunft.net
> *Betreff:* Re: SoftReference incorrect javadoc?
>
> Looks like the mailing list removed the attachment. It's short enough to
> be in the email body.
>
> SoftRefTest.java:
> ```
> import java.lang.ref.SoftReference;
> import java.util.ArrayList;
>
> public class SoftRefTest {
> static final int count = 2000000;
>
> public static void main(String[] args) throws Exception {
> ArrayList<SoftReference<Instance>> instances = new ArrayList<>();
> long start = System.currentTimeMillis();
>
> for (int i = 0; i<count; i++) {
> instances.add(new SoftReference<>(new Instance()));
>
> if (i % 100000 == 0 && i > 0) {
> Thread.sleep(100); // give GC time to breathe
> System.out.println(i + " instances created; free=" +
> Runtime.getRuntime().freeMemory() / 1024 / 1024 + "M");
> }
> }
>
> System.out.println("time taken: " + (System.currentTimeMillis() -
> start));
> }
>
> }
>
> class Instance {
> static int finalizedCount = 0;
> String[] occupySomeHeap = new String[50];
>
> @Override
> protected void finalize() throws Throwable {
> super.finalize();
> finalizedCount++;
> if (finalizedCount % 100000 == 0) {
> System.out.println(finalizedCount + " instances finalized");
> }
> }
> }
> ```
>
> On 17/04/19 1:59 pm, Michael Pollmeier wrote:
>> Hi Per,
>>
>> While testing different JVMs I realized that it's fixed in openjdk 11,
>> e.g. openjdk version "11.0.1" 2018-10-16 LTS (zulu build), maybe by this
>> commit: https://hg.openjdk.java.net/jdk/jdk/rev/6464882498b5
>> That's great to know, but is it worth updating the javadocs of older
>> versions?
>>
>> To reproduce it I attached a simple SoftRefTest.java to easily reproduce
>> it. It allocates (only) softly referenced objects that occupy some heap,
>> occasionally printing counts (instantiated, finalized, free heap).
>>
>> Usage:
>> javac SoftRefTest.java
>> java -Xms256m -Xmx256m SoftRefTest
>>
>> Output:
>> 100000 instances created; free=212M
>> 200000 instances created; free=181M
>> 300000 instances created; free=152M
>> 400000 instances created; free=121M
>> 500000 instances created; free=93M
>> 600000 instances created; free=61M
>> 700000 instances created; free=33M
>> Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
>> at Instance.<init>(SoftRefTest.java:27)
>> at SoftRefTest.main(SoftRefTest.java:12)
>>
>> Interpretation:
>> It doesn't free any of the only softly referenced objects, resulting in
>> an OutOfMemoryError, contradicting the 'guarantee' in the javadoc.
>>
>> Workaround: if you additionally configure
>> `-XX:SoftRefLRUPolicyMSPerMB=0`, it finalizes them and doesn't run out
>> of memory.
>>
>> Tested with:
>> openjdk version "1.8.0_212"
>> java version "1.8.0_144" (oracle)
>> openjdk version "9.0.4.1" (zulu build)
>> openjdk version "10.0.2" 2018-07-17 (zulu build)
>>
>> Cheers
>> Michael
>>
>>
>> On 16/04/19 6:27 pm, Per Liden wrote:
>>> Hi Michael,
>>>
>>> On 4/16/19 4:19 AM, David Holmes wrote:
>>>> Hi Michael,
>>>>
>>>> Re-directing to core-libs-dev and hotspot-gc-dev.
>>>>
>>>> Thanks,
>>>> David
>>>>
>>>> On 16/04/2019 12:14 pm, Michael Pollmeier wrote:
>>>>> Quoting
>>>>>
> https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ref/SoftReference.html
>
>>>>>
>>>>>
>>>>>
>>>>>> All soft references to softly-reachable objects are guaranteed to
> have
>>>>> been cleared before the virtual machine throws an OutOfMemoryError
>>>>>
>>>>> That statement was true when soft references were first introduced in
>>>>> java 1.2, but from java 1.3.1 the jvm property
>>>>> `-XX:SoftRefLRUPolicyMSPerMB` was introduced.
>>>
>>> That statement is still true. When the GC gets into a situation where it
>>> is having trouble satisfying an allocation, then SoftRefLRUPolicyMSPerMB
>>> will be ignored and all soft references will be cleared, before the GC
>>> gives up and throws an OOME.
>>>
>>>>> It defaults to 1000 (milliseconds), meaning that if there’s only 10MB
>>>>> available heap, the garbage collector will free references that have
>>>>> been used more than 10s ago. I.e. everything else (including young
>>>>> softly reachable objects) will *not* be freed, leading to an
>>>>> OutOfMemoryError, contradicting the above quoted 'guarantee'.
>>>>>
>>>>> That's also the behaviour I observed on various JREs. Would you agree,
>>>>> i.e. should I propose an updated doc?
>>>
>>> Could you elaborate on what kind of test you did to come to this
>>> conclusion? Preferably provide a re-producer. In OOME situations, if a
>>> SoftReference isn't cleared, it is typically because you have
>>> unknowingly made it strongly reachable.
>>>
>>> cheers,
>>> Per
>>>
>>
>
More information about the jdk-dev
mailing list