Canonicalized Mapping and Weakreference

Asked

Viewed 255 times

11

I would like someone to explain the concept (and applications) of Canonicalizing Mapping and how your reference implementation would work using Weakhashmap.

1 answer

8


Hello @Reginaldo Soares,

To properly understand the workings of a Canonicalized Mapping, let’s first understand the actions of the Garbage Collector and the reference types that exist in Java.

In Java we do not release memory programmatically

As is already known by programmers, Java is a language in which it is not necessary to allocate and de-locate memory, as it is in C++. Within the Java Virtual Machine the Agent known as the Garbage Collector releases memory of objects that no longer have reference, in other words every created object, in general has a reference to it once the scope of this reference ends, or it is nullified - variable = null - the object in question can already be collected by Garbage Collector.

Other types of reference

The behavior described above is that of most applications that run on JVM. This type of reference is called Strong Reference. Objects that have String References or strong references, can only be collected once there is no more strong reference to them, in an event where the JVM has no memory available for creating new objects, and Error Outofmemoryerror java heap space is released, since the JVM cannot release objects with this type of reference.

java.lang.ref - Softreference, Weakreference and Phantomreference

In the java.lang package we find other reference types that can be used for interaction with Garbage Collector, let’s analyze each of them

Softreference

This reference type will have another interaction within the application, the object for which there are only references of type - light references - will be collected just before a Outofmemoryerror heap space be released. Implementations of the Java Virtual Machine that follows the specifications must collect objects that only have Softreferences before running out of memory.

Let’s look at an example - In the code below, we are creating an Arraylist to store Bigdecimal objects, interacting and adding to each loop the next number, going from 0 to 10 million. On my machine after number iteration 17864218 The Exception Nullpointerexception is thrown.

import java.lang.ref.SoftReference;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;



public class Main {
    public static void main(String[] args) {
        //Declaracao de uma SoftReference - note como ela funciona como um Wrapper
        SoftReference<List<BigDecimal>> listString = new SoftReference<>(new ArrayList<>(100000));
        for(int i = 0; i < 100000000; i++){
            System.out.println(i); 
            // o método get retorna o objeto ArrayList
            // após a iteracao de numero 17864218 este método retornou null, pois o objeto foi coletado
            listString.get().add(new BigDecimal(i));
        }
    }
}

Upshot:

Exception in thread "main" java.lang.NullPointerException
    at org.greentea.Main.main(Main.java:15)

(switch to a normal reference, Strong Reference, and you’ll see Outofmemoryerror)

Weakreference

Weakrererences unlike Softreferences are weak, since there is no other reference to any object that has only Weakrerefences, Soft or Strong, this object must be collected in the next Garbage Collector cycle.

Let’s take an example

In the code below we are creating a new instance of an Object, marking it to a Weakreference to a Strongreference, calling it the Garbage Collector, then we observe that the Weakreference is not yet collected, as there is still a Strong Reference to Object, in the sequence, we cancel(null out) the variable strongRef(reference of type Strong), we call again the Garbage Collector and this is the result: null - even with reference the Object was collected

import java.lang.ref.WeakReference;

public class Main {
    public static void main(String[] args) throws Exception{

        // Declarando uma variável de referência fraca
        WeakReference<Object> weakRef = new WeakReference<>(new Object() {
            @Override
            public String toString() {//Customizando toString para fins didaticos
                return "I am a dummy object!";
            }
        });

        // Apontando mais uma referência para a String Test
        Object strongRef = weakRef.get();

        System.gc();//Nao utilizar este metodo em producao

        Thread.sleep(1000);

        //Aida ha uma String Reference para o Object, entao ele nao e coletado
        System.out.println(weakRef.get());

        //Null out stringRef
        strongRef = null;

        System.gc();

        Thread.sleep(2000);

        //Agora apenas restou a WeakReferencia, mesmo com ela, o Objeto ja esta elegivel
        System.out.println(weakRef.get());

    }
}

Upshot:

I am a dummy object!
null

Phamtomreference

Phamtomreferences are ghost references, which are no longer possible to access the object, usually used as substitutes for the Object.finanlize method. The finalize method was created to release resources used by the Object, such as connections, open files, etc. It is not recommended to use this method, that is, it is not reliable to overwrite it for these purposes, one of the reasons is that this method allows the resurrection of the object, In addition to affecting the performance of Garbage Collector, as it is the invocation, many finalizer == more time to collect Objects not reachable by references.

Phantom References to the Rescue

Phantom(ghosts) references can be used to perform actions before an object is collected, in a safe way. In the constructor of a java.lang.ref.PhantomReference, we must specify a queue - java.lang.ref.ReferenceQueue where the phantom reference will be aligned once the referenced object becomes "phantom Reachable", achieved only by a phantom reference. What initially sounds a little confusing is that although a ghost reference continues to keep the referenced object in a particular field (unlike Weak or soft references), its Getreference() method always returns null. This is so that it is not possible to make the object strongly accessible again().

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

public class Main {
    public static void main(String[] args) throws Exception{

        class Foo{
            private String foo = "abc";
            @Override
            public String toString() {
                return "I am a foo";
            }
        }

        Foo f = new Foo();

        ReferenceQueue<Foo> q = new ReferenceQueue<Foo>();

        PhantomReference<Foo> phantomRef = new PhantomReference<Foo>(f, q);

        System.gc();

        System.out.println(f);

        f = null;

        System.gc();

        System.out.println("Esta na fial de referencias fantasmas? " + phantomRef.isEnqueued());

        PhantomReference<Foo> referenceFromQueue = null;

        while ( (referenceFromQueue =  (PhantomReference<Foo>) q.poll()) != null) {
            System.out.println("Sempre retorna null, certo? -> "+referenceFromQueue.get());
            referenceFromQueue.clear();
        }
    }
}

Upshot:

 I am a foo
Esta na fial de referencias fantasmas? true
null

Canonicalized Mapping and Weakhashmap

A "canonicalized" mapping allows to keep an instance of the object in question in memory and all other objects that need it, can access it. This is the moment where Weaks References can help.

The short answer is that Weakreference objects can be used to create pointers to objects in your system while still allowing these objects to be collected once they are outside the scope. For example:

 class Registrador {
     private Set objetosRegistrados = new HashSet();

     public void registrar(Object object) {
         objetosRegistrados.add( object );
     }
 }

Any recorded object will never be collected by the GC because there is a reference to it stored in the objectRegistered Set. So how do we solve this?

 class Registrador {
     private Set objetosRegistrados = new HashSet();

     public void registrar(Object object) {
         objetosRegistrados.add( new WeakReference(object)  );
     }
 }

Weakhashmap

The java.util.Weakhashmap class uses weak references to provide only a Canonicalization mapping. It is possible to add key-value pairs (Weakhashmap implements the Map interface) to a Weakhashmap instance through the put() method, just as you can to an instance of any class that implements java.util.Map. But inside, the Weakhashmap, the main objects are realized through weak reference objects that are associated with a reference queue. If the Garbage Collector determines that one of the Keys is weakly accessible, it will clean and line up any weak reference objects that refer to that key. The next time Weakhashmap is accessed, it will search the reference queue and extract all the weak reference objects that Garbage Collector put there.

  • 4

    I can’t thank you so full answer/explanation!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.