SoftReference incorrect javadoc?
Per Liden
per.liden at oracle.com
Wed Apr 17 18:12:41 UTC 2019
On 04/17/2019 06:38 AM, Michael Pollmeier wrote:
> 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.
Whether the VM clears a SoftReference or not is unrelated to whether the
referent has a finalize method. However, a finalize method affects when
the memory can be reclaimed.
This behavior is the same across all JDK versions, there's nothing
special about 11 here.
cheers,
Per
>
> 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