Implementation of reference and dynamic proxy in Java
As we know, the difference between dynamic agent (JDK's dynamic agent here) and static agent is that its real agent class is generated dynamically. But how to generate it, what content the generated agent class contains, what form it exists in, and why it must be based on the interface?
If you look at the source code of the dynamic proxy (java.lang.reflect.proxy), you will find that its principle is very simple (the generation of real binary class files is completed in local methods, not in the source code), but it uses a buffer class java.lang.reflect.weakcache < classloader, class [], class >, which uses weak references to build.
Among the three special references of JDK, weak reference is the most widely used, and its characteristics are the clearest. Relatively speaking, the other two logics are slightly obscure, and the comments in the source code are vague. This paper will briefly introduce the behavior characteristics of several references, and then analyze some practical application scenarios of weak references, including the implementation in dynamic proxy. This article will include the following:
Reference types in JDK
Effects of different reference types on GC behavior
Implementation of reference type
ThreadLocal's use of weak references
Implementation of weak reference by dynamic proxy
How virtual references cause memory leaks
Type of reference in JDK
All the running logic of Java is based on reference, and its form is similar to immutable pointer, so there will be some winding concepts in Java. For example, the parameter passing of function in Java is value passing, but the value mentioned here is actually the value of reference, so you can modify the value of its object through the parameters of a function. On the other hand, there are some basic data types in Java. They are not referenced and pass real values. Therefore, the value of parameters cannot be modified inside the function.
There are several kinds of references in Java:
1. Strong reference
References to all objects are strong references by default. In ordinary code, strong references are passed between assignment statements. If an object can be accessed by a thread (alive, the same below) through strong references, it is called strongreachable.
Strongly reachable objects are not recycled by GC.
2. Soft reference (softreference < T >)
When an object is not strongly reachable but can be accessed by a thread through soft reference, it is called soft reachable.
References to soft reachable objects are cleared only when there is insufficient memory so that they can be recycled by GC. At this point, the JVM does not guarantee when to clear soft references, but it can guarantee that soft reachable objects will be cleared before oom. At the same time, the JVM does not guarantee the recycling order of soft reachable objects, but it is mentioned in the oraclejdk document that recently created and recently used soft reachable objects are often recycled at last, which is similar to LRU.
For information on when soft reachable objects are recycled, refer to the Oracle documentation.
3. Weak reference (WeakReference < T >)
When an object is neither strongly reachable nor soft reachable, but can be accessed by a thread through a weak reference, it is called weakly reachable.
Weak reference is the most widely used reference type in addition to strong reference, and its characteristics are simpler. When an object is weakly reachable, the JVM will clear the weak reference on the object and then recycle the object.
4. Phantom reference (phantom reference < T >)
When an object is unreachable through the above accessibility analysis and has been finalized, but a virtual reference points to it, it is phantom reachable.
Virtual reference is the most bizarre and difficult to use, which will be discussed later.
Virtual reference will not affect GC. Its get () method always returns null. Its only use is that after gcfinalize an object, it will be placed in the specified queue. This queue will be described below.
Principles behind different GC behaviors
Accessibility analysis of jvmgc
The GC of the JVM judges whether an object can be recycled through reachability analysis. Its basic idea is to traverse all objects on the chain starting from gcroots. When there is no direct or indirect reference connection between an object and gcroots, it is called an unreachable object, which proves that the object is unavailable.
Furthermore, Java defines four different reachability as described above to implement more refined GC policies.
Finalize and ReferenceQueue
For ordinary strong reference objects, if they become unreachable, GC will usually finalize them (the main purpose of finalizing is to allow users to customize the process of releasing resources, usually the resources used in local methods), and then destroy and recycle their objects. However, for the three references discussed in this article, there may be other things to do in this process:
GC decides whether to clear these references according to the agreed rules
As mentioned in the previous section, each reference type has agreed processing rules.
If they register a reference queue, after finalizing the object, the referenced object is placed in the queue.
It is mainly used to enable developers to be notified of the destruction of objects. Of course, for example, virtual references, their references will not be automatically cleared, so it can prevent the referenced objects from being recycled.
State of reference (Java. Lang.ref.reference < T >) object
The "reference object" here refers to the Java class lang.ref. Reference < T > the object produced. On this object, the reference to the "target object" that needs special processing is maintained.
A reference object has four states. According to its relationship with its registered queue, it can be divided into the following four states:
Active
The initial state of the reference object indicates that the GC should process the object according to special logic. The general method is as mentioned in the previous section.
Pending
If a reference object is registered in the queue, it will enter this state before joining the queue.
Enqueued
After a reference object joins the queue, it enters this state.
Inactive
After a reference object is out of the queue, or there is no queue registered, its queue is a special object Java lang.ref. ReferenceQueue. Null indicates that this object is no longer useful.
Practical application of several references
In daily development, references other than strong references are unlikely to be used. These special references need to be considered only when dealing with some performance sensitive logic. Here are some relevant practical examples to analyze their use scenarios.
Soft reference
The use of weak references is relatively simple. For example, the localcache in guava uses softreference as the cache.
Weak reference
Weak references are often used. As can be seen from the above description: for a "target object a", if there is a strong reference pointing to it, a can be accessed from a weak reference. Once there is no strong reference pointing to it, it can be considered that a cannot be accessed from this weak reference (there may be deviation in the actual situation).
According to this feature, the JDK notes that weak references are usually used as canonicalizing mapping. To sum up, the mapping table has two features:
If the key (or value) in the table still has a strong reference, the value can be accessed through the key; otherwise, it cannot be accessed
In other words, as long as you have the original key, you can access the value.
The mapping table itself does not affect the GC of key or value
This feature is used in many places in JDK. The following are two representative examples.
1.ThreadLocal
The principle of ThreadLocal is relatively simple. A ThreadLocal with ThreadLocal as the key is maintained in the thread Threadlocalmap object threadlocals, where the entry is as shown in code 1:
The reference relationship is shown in the following figure:
Reference relationship in ThreadLocal
As can be seen from the above figure, when reference 2 is cleared (ThreadLocal object is no longer used), if reference 4 is a strong reference, object 1 and object 2 will never be released as long as the thread object is not dead, whether reference 1 still exists or not.
2. Dynamic agent
Dynamic proxy is a very important feature in the Java world. It is very important for business logic that needs to do AOP. JDK itself provides a reflection based dynamic proxy mechanism. Its principle is to dynamically generate proxy classes through predefined interfaces and proxy them to the invocationhandler instance. The dynamic proxy of JDK is very simple to use, as shown in code 2 below:
Implementation principle of dynamic agent
About the dynamic agent in Java, we first need to understand a common design pattern - agent pattern. For the agent, it can be divided into static agent and dynamic agent according to the time point of creating the agent class.
Proxy mode is a commonly used java design mode. Its feature is that the proxy class has the same interface with the delegate class. The proxy class is mainly responsible for preprocessing messages for the delegate class, filtering messages, forwarding messages to the delegate class, and post-processing messages. There is usually an association relationship between proxy class and delegate class. The object of a proxy class is associated with the object of a delegate class. The object of the proxy class itself does not really implement the service, but provides a specific service by calling the relevant methods of the object of the delegate class. In short, when accessing the actual object, we access it through the proxy object. The proxy mode introduces a certain degree of indirectness when accessing the actual object, because this indirectness can be added for a variety of purposes.
See: proxy pattern principle and implementation code sharing of Java design pattern
Classes and class loaders refer to each other, and the memory leakage of class loaders may cause serious problems. If you are interested, you can see this article: reloading Java classes 201: how do classloader leads happen?
On Java annotation and dynamic proxy
Example of network connection method using java proxy
Principle and implementation of proxy pattern in Java design pattern