一.Java 强引用 软引用 弱引用 虚引用的使用场景以及系统调用时机
Java的引用强引用直接使用了对象的地址,软引用 弱引用 虚引用 都在引用对象之间隔了一层通过这些特殊的对象间接引用了我们需要的对象。
1.强引用:
Object object = new Object();
object 这个Object类型的变量直接引用了new Object() 这个类型的在内存中开辟的这块地址空间的地址。这是我们常见的编码方式。使用场景有:方法的局部变量,jni变量,类变量,概括起来就是GC ROOT 可达的都是强引用。
1.object如果前面加上static修饰那么这个Object 类型的变量就会在常量区定义那么会一直引用指着这块开辟的地址内存不会释放。
2.object这个变量在栈内引用已经执行完了并且没有其他地方引用这个地址时这块地址的引用数为0那么这块地址可以被释放。
3.只要有引用在,垃圾回收器永不处理,jvm宁愿自己崩了一般报(OutOfMemoryError)错误,也不去回收这个这类对象使用的内存。所以会造成内存泄漏和内存溢出。
4.源代码
class FinalReference<T> extends Reference<T> {
public FinalReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
2.软引用:
Objext obect = new Object();
SoftReference<Object> sfObject = new SoftReference<Object>(obj);
sfObject.get();//有时候会返回null
1.软引用即在生成的对象和产生的地址之上再封装一层。我们需要使用这个对象时通过软引用间接的获取到这个对象的使用。
2.object的释放在jvm内存不足时object指定的内存块释放。
3.软用可以用在程序中的缓存功能的实现,比如图片缓存,对象缓存等等。
4.在Android中 SoftReference 或者 WeakReference做图片缓存是不推荐的,因为Android内存小会更频繁的对于这些引用的对象进行回收,回收后又会频繁的对这些对象开辟内存空间。所以Android官方推荐最新的解决办法,这个类包含在android-support-v4包中,是采用LruCache以及DiskLruCache。Android中可以使用SoftReference 或者WeakReference 用在把上下文传入静态工具中以免造成activity内存泄漏。后续讲这类工具时在细分讲解。
5.源代码
public class SoftReference<T> extends Reference<T> {
/**
* Timestamp clock, updated by the garbage collector
*/
static private long clock;
/**
* Timestamp updated by each invocation of the get method. The VM may use
* this field when selecting soft references to be cleared, but it is not
* required to do so.
*/
private long timestamp;
/**
* Creates a new soft reference that refers to the given object. The new
* reference is not registered with any queue.
*
* @param referent object the new soft reference will refer to
*/
public SoftReference(T referent) {
super(referent);
this.timestamp = clock;
}
/**
* Creates a new soft reference that refers to the given object and is
* registered with the given queue.
*
* @param referent object the new soft reference will refer to
* @param q the queue with which the reference is to be registered,
* or <tt>null</tt> if registration is not required
*
*/
public SoftReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
this.timestamp = clock;
}
/**
* Returns this reference object's referent. If this reference object has
* been cleared, either by the program or by the garbage collector, then
* this method returns <code>null</code>.
*
* @return The object to which this reference refers, or
* <code>null</code> if this reference object has been cleared
*/
public T get() {
T o = super.get();
if (o != null && this.timestamp != clock)
this.timestamp = clock;
return o;
}
}
6.在新建SoftReference对象和调用SoftReference.get时都会使timestamp更新为clock的值。而clock代表的是上次gc的时间。
SoftRefLRUPolicyMSPerMB默认为1000,即1s。代表每1MB空闲空间大小SoftReference保留1s。
-XX:SoftRefLRUPolicyMSPerMB
设置每兆堆空闲空间中SoftReference的存活时间,默认值是1s 。(softly reachable objects will remain alive for some amount of time after the last time they were referenced. The default value is one second of lifetime per free megabyte in the heap)
3.弱引用:
Object object = new Object();
WeakReference<Object> wfObect = new WeakReference<Object>(object);
wfObject.get();//有时返回为null
wfObject.isEnQueued();//返回引用状态 返回是否被垃圾回收器标记为即将回收的垃圾
1.弱引用是在第二次垃圾回收时回收,短时间内通过弱引用取对应的数据,可以取到,当执行过第二次垃圾回收时,将返回null。
2.弱引用主要用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的isEnQueued方法返回对象是否被垃圾回收器标记。
3.只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
4.源代码
public class WeakReference<T> extends Reference<T> {
/**
* Creates a new weak reference that refers to the given object. The new
* reference is not registered with any queue.
*
* @param referent object the new weak reference will refer to
*/
public WeakReference(T referent) {
super(referent);
}
/**
* Creates a new weak reference that refers to the given object and is
* registered with the given queue.
*
* @param referent object the new weak reference will refer to
* @param q the queue with which the reference is to be registered,
* or <tt>null</tt> if registration is not required
*/
public WeakReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
4.虚引用:
Object object = new Object();
PhantomReference<Object> pfObject = new PhantomReference<Object>(object);
pfObject.get() //永远返回为null
pf.isEnQueued();//返回是否从内存中已经删除
1.虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引用。
2.垃圾回收器扫描时即回收内存的使用。
3.虚引用主要用于检测对象是否已经从内存中删除。
4.源代码
public class PhantomReference<T> extends Reference<T> {
/**
* Returns this reference object's referent. Because the referent of a
* phantom reference is always inaccessible, this method always returns
* <code>null</code>.
*
* @return <code>null</code>
*/
public T get() {
return null;
}
/**
* Creates a new phantom reference that refers to the given object and
* is registered with the given queue.
*
* <p> It is possible to create a phantom reference with a <tt>null</tt>
* queue, but such a reference is completely useless: Its <tt>get</tt>
* method will always return null and, since it does not have a queue, it
* will never be enqueued.
*
* @param referent the object the new phantom reference will refer to
* @param q the queue with which the reference is to be registered,
* or <tt>null</tt> if registration is not required
*/
public PhantomReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
二.源码解析
1.首先我们看看Java中引用类在哪个文件夹里。这里使用的jdk版本是jdk1.8
2.对象引用概述
在jdk1.2以前的版本,对象引用类型单一只有强引用类型,在1.2版本以后对引用类型做了扩充,把引用对象做了四个级别的设置更好的对对象的生命周期进行管控。这4种级别由高到低依次为:强引用、软引用、弱引用和虚引用。
3.对象的生命周期和回收队列
1.所有的对象引用都继承了在package java.lang.ref包下面的 Reference<T> 类。Reference类首先把内存分为4种状态Active,Pending,Enqueued,Inactive。
.Active 一般来说new出来的对象一开始设置的状态是active
.Pending 待定中,指快放入回收队列的对象
.Enqueued 就是对象的内存已经被gc回收了
.Inactive最终状态,不可改变对象
2.ReferenceQueue 引用队列,在检测到适当的可到达性更改后,垃圾回收器将已注册的引用对象添加到队列中,ReferenceQueue实现了入队(enqueue)和出队(poll),还有remove操作,内部元素head就是泛型的Reference。
4.对象使用完的垃圾回收
1.回收的区域
jvm虚拟机划分使用的内存区域有堆区,栈区,静态常量区,方法区等。新建的对象都放在堆区,因此需要回收的区域就是分配建立对象的堆区。
2.回收的对象
1.gc root 不在引用的对象。即现在程序不需要使用的对象需要释放掉使用的内存
3.回收的方法
1.可达性分析 从gc root这类对象开始,向下搜索。
gc root 的种类:
Class:由系统的类加载器加载的类对象
Static Fields
Thread:活着的线程
Stack Local: java方法的局部变量或参数
JNI Local: JNI方法中的局部引用
JNI Global: 全局的JNI引用
Monitor used: 用于同步的监控对象
2.引用计数分析
5.Java的分代回收机制
1.将对象依据使用时长进行分类,分成新生类,中年类,老年类等。
6.leakscannary的原理