虚引用
虚引用在垃圾回收时候,抢救不了了。对象回收的时候直接回收,如果用ReferenceQueue,那么在回收时候通过这个队列,可以人为做些处理。软引用弱引用先置位referent为null回收堆内存,然后把虚引用对象加入队列,最后在队列里面回收虚引用对象。
虚引用必须要和ReferenceQueue结合使用,软引用弱引用可以不和ReferenceQueue结合使用。
强引用 : 就是普通的引用. 内存不足抛 Out of Memory 异常
软引用(SoftReferenve) : 内存充足的情况下不会被回收,内存不充足的情况下才会被回收。能够很好地规避OOM异常。
弱引用(WeakReference) : 当垃圾回收机制运行时, 弱引用引用的对象就会被回收掉.
// 新建一个引用队列
ReferenceQueue<TestObject> referenceQueue = new ReferenceQueue<>();
// 建立一个TestObject的弱引用
SoftReference<TestObject> reference = new SoftReference<>(new TestObject(), referenceQueue)
弱引用和软引用在创建的时候都可以传进去一个引用队列(当然也可以不使用引用队列), 当弱引用和软引用引用的对象需要进行回收的时候, JVM都是先将其referent字段设置成null,之后将软引用或弱引用对象本身,加入到关联的引用队列中。也就是说JVM先回收堆对象内存,然后才将软引用或弱引用本身加入到引用队列。
// 创建一个引用队列
ReferenceQueue<TestObject> referenceQueue = new ReferenceQueue<>();
PhantomReference reference = new PhantomReference<>(new TestObject(), referenceQueue);
而虚引用(PhantomReference) 不同, 他必须和引用队列 (ReferenceQueue)联合使用, 若GC启动时, 则将引用对象传到它的引用队列中去. 但是不会将虚引用的referent字段设置成null, 也就是不会释放虚引用指向的TestObject的堆对象内存空间。
如果虚引用引用的对象重写了finalize方法, 在虚引用对象传到它的引用队列之前还会调用对象的finalize方法, 但是调用之后内存不会回收.
你可以通过手动调用PhantomReference.clear()方法来释放虚引用指向的的堆对象内存空间。
虚引用的存在更倾向于实现程序员对内存回收的细粒度性控制, 当虚引用确定会被回收之后, 会向应用程序发送通知, 此时程序员进行对内存清理的细微操作.
public static void main(String[] args) { Object obj = new Object(); ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>(); WeakReference<Object> weakRef = new WeakReference<Object>(obj, refQueue); System.out.println(weakRef.get());//返回weakRef里面的obj System.out.println(refQueue.poll());//队列灭有元素 obj = null;//只有weakRef 指向new Object()内存,不置位null,gc时候不会将weakRef 的eferent被置位了null,也不会将weakRef加入refQueue队列 System.gc(); System.gc(); System.gc(); System.gc();//System.gc()是告诉JVM这是一个执行GC的好时机,但具体执不执行由JVM决定, System.out.println(weakRef.get());//referent被置位了null System.out.println(refQueue.poll());//队列里面有一个元素weakRef但是weakRef的referent被置位了null }
public class Test0009 { public static void main(String[] args) throws InterruptedException { Object obj = new Object(); ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>(); PhantomReference<Object> phanRef = new PhantomReference<Object>(obj, refQueue); System.out.println(phanRef.get());//null,phanRef里面有元素但是一直返回null,因为PhantomReference重写了Reference的get方法,写死了返回null。 System.out.println(refQueue.poll());//队列为空, obj = null;//不置位null,phanRef里面有元素,队列为空。 System.gc(); System.gc(); System.gc(); System.out.println(phanRef.get());//phanRef里面仍然有元素,referent并没有像弱引用软引用那样置位空, System.out.println(refQueue.poll());//队列有元素, } }
class Registry { private Set registeredObjects = new HashSet(); public void register(Object object) { registeredObjects.add( object ); } } 所有我添加进 registeredObjects 中的object永远不会被GC回收,因为这里有个强引用保存在registeredObjects里,
object 内存对象被2个强引用关联。另一方面如果我把代码改为如下:
class Registry { private Set registeredObjects = new HashSet(); public void register(Object object) { registeredObjects.add( new WeakReference(object) ); } } 现在如果GC想要回收registeredObjects中的object,object 内存对象被1个强引用1个弱引用关联,便能够实现了,
同样在使用HashMap如果想实现如上的效果,一种更好的实现是使用WeakHashMap
强引用:一直不回收
软引用:内存不足回收
弱引用:gc就回收
虚引用: “虚引用”顾名思义,就是形同虚设,一个对象仅持有虚引用,那么它就和没有任何引用一样。虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用必须和引用队列 (ReferenceQueue)联合使用。
当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。
虚引用里面的对象没有强引用时候,开始回收,加入到队列去,并不会置referent为null。
软引用弱引用里面的对象没有强引用时候,开始回收,加入到队列去,置referent为null。
public class MyDate extends Date { /** Creates a new instance of MyDate */ public MyDate() { } // 覆盖finalize()方法,finalize()函数是在JVM回收内存时执行的, protected void finalize() throws Throwable { super.finalize(); System.out.println("obj [Date: " + this.getTime() + "] is gc"); } public String toString() { return "Date: " + this.getTime(); } }
虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个仅仅持有虚引用的对象,和没有引用几乎是一样的,随时都有可能被垃圾回收器回收。当试图通过虚引用的get()方法取得强引用时,总是会失败。并且,虚引用必须和引用队列一起使用,它的作用在于跟踪垃圾回收过程。
当你的虚引用所引用的对象已经执行完finalize函数的时候,就会把对象加到queue里面。
广义的堆外内
-Xmx的值是新生代和老生代的和的最大值,-XX:MaxPermSize来指定持久代的最大值,Java堆的最大值其实是-Xmx和-XX:MaxPermSize的总和。
那么剩下的都可以认为是堆外内存(广义的)了,这些包括了jvm本身在运行过程中分配的内存,codecache,jni里分配的内存,DirectByteBuffer分配的内存等等。
狭义的堆外内存
这个主要是指java.nio.DirectByteBuffer在创建的时候分配内存。/