Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8308993

PhantomReferences doesn't become enqueued if referent has circular references

    XMLWordPrintable

Details

    • generic
    • generic

    Description

      ADDITIONAL SYSTEM INFORMATION :
      OS: windows 10
      test java version: OpenJDK 1.8.0_345, OpenJDK 11.0.17, OpenJDK 17, OpenJDK 19.0.1


      A DESCRIPTION OF THE PROBLEM :
      If a referent object which register PhantomReference to ReferenceQueue has some circular references, it will never enqueued .


      ---------- BEGIN SOURCE ----------
      define the flow class:

      ```java
      public class House {
          private Address address;

          Address getAddress() {
              if (address == null) address = new Address(this);
              return address;
          }

          public void close() {
              System.out.println("close house " + this);
          }
      }

      public class Address {
          private final House house;

          Address(House house) {
              this.house = house;
          }

          House getHouse() {
              return house;
          }
      }

      public class AddressPhantomReference extends PhantomReference<Address> {

          private final Runnable thunk;

          AddressPhantomReference(Address referent, ReferenceQueue<? super Address> q) {
              super(referent, q);
              thunk = referent.getHouse()::close;
          }

          public void finalizeResources() {
              // free resources
              thunk.run();
              System.out.println("clearing ...");
          }
      }
      ```

      the test class use AddressPhantomReference to phantom references refer to object Address

      ```java
      public class Test {
          public static void main(String[] args) throws InterruptedException {

              ReferenceQueue<Address> referenceQueue = new ReferenceQueue<>();
              Set<AddressPhantomReference> references = new HashSet<>();

              House house = new House();
              Address address = house.getAddress();

              System.out.println("create House " + house);
              System.out.println("create Address " + address);

              references.add(new AddressPhantomReference(address, referenceQueue));

              house = null;
              address = null; // change house to unreachable and address to phantom reachable.

              System.gc();

              while (true) {
                  AddressPhantomReference reference = (AddressPhantomReference) referenceQueue.poll();
                  if (reference != null) { // will not be execute!
                      reference.finalizeResources();
                      reference.clear();
                      references.remove(reference);
                  }
                  if (references.isEmpty()) break;
                  Thread.sleep(1000);
              }
          }
      }
      ```

      when the house object is unreachable and address object is phantom reachable, the address object not enqueued to ReferenceQueue, and the garbage collector will never reclaime those object, it will cause memory leak.

      ---------- END SOURCE ----------

      FREQUENCY : always


      Attachments

        1. Address.java
          0.2 kB
        2. AddressPhantomReference.java
          0.5 kB
        3. House.java
          0.3 kB
        4. Test.java
          1 kB

        Activity

          People

            Unassigned Unassigned
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: