JVM之_1_引用
前言
Github:https://github.com/HealerJean
垃圾回收的机制主要是看对象是否有引用指向该对象。 java对象的引用包括 强引用,软引用,弱引用,虚引用
1、强引用
强引用无需引入其他实体类,所引用的对象为 若该对象被清理将导致程序无法进行的对象。也就是平常最常使用的引用。JVM宁愿抛出OutOfMemory异常,也不会尝试回收所关联的对象。使用形式如下
当运行至Object[] objArr = new Object[1000];这句时,如果内存不足,JVM会抛出OOM错误也不会回收object指向的对象。不过要注意的是,当fun1运行完之后,object和objArr都已经不存在了,所以它们指向的对象都会被JVM回收。
public static void main(String[] args) {
new Main().fun1();
}
public void fun1() {
Object object = new Object();
Object[] objArr = new Object[1000];
}
2、软引用(java.lang.ref.SoftReference)
软引用需引入java.lang.ref.SoftReference类,所引用的对象为 仍有用但非必须的对象。被软引用关联的对象,内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用
作用:可以应用为某些缓存内容,加快程序速度,同时又不影响内存使用。比如网页缓存、图片缓存等。使用软引用能防止内存泄露,增强程序的健壮性。
也就是说,一旦SoftReference保存了对一个Java对象的软引用后,在垃圾线程对 这个Java对象回收前,SoftReference类所提供的get()方法返回Java对象的强引用。 另外,一旦垃圾线程回收该Java对象之 后,get()方法将返回null。
Object object=new Object();
SoftReference aSoftRef=new SoftReference(object);
aSoftRef.get();
package com.hlj.moudle.Java02垃圾收集器与内存分配策略;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
/**
* @Description 软引用
* @Author HealerJean
* @Date 2019/2/7 下午7:36.
软引用需引入java.lang.ref.SoftReference类,
所引用的对象为 仍有用但非必须的对象。被软引用关联的对象,将在抛出oom异常之前回收。
可以应用为某些缓存内容,加快程序速度,同时又不影响内存使用。使用形式如下
*/
public class Jvm02Refqueue {
@SuppressWarnings({ "rawtypes", "unchecked" })
public static void main(String[] args) throws InterruptedException {
//创建软引用
ReferenceQueue<SoftReference<G>> rq = new ReferenceQueue<SoftReference<G>>();
SoftReference[] srArr = new SoftReference[1000];
//在 这个for循环中 new new G() 的时候
//当执行到一定次数的是,会造成垃圾收集器回收内存(因为内存不够用了)
for(int i = 0; i < srArr.length; i++){
srArr[i] = new SoftReference(new G(), rq);
}
//获取被清除部分
int n=0;
for(int i = 0; i < srArr.length; i++){
if(srArr[i].isEnqueued()){ //方法返回对象是否被垃圾回收器标记
srArr[i]=null;
n++;
}
}
System.out.println("第一次GC,清除了"+n+"个");
//下面的方法,会强制再执行一遍垃圾收集器,(用来测试软引用是否被回收)
for(int i=0;i<10000;i++){
G g=new G();
}
int m=0;
for(int i = 0; i < srArr.length; i++){
if(srArr[i]!=null&&srArr[i].isEnqueued()){
srArr[i]=null;
m++;
}
}
System.out.println("第二次GC,清除了"+m+"个");
}
}
//为了占据内存
class G{
private int [] big=new int[1000000];
}
/*
output:
第一次GC,清除了971个
第一次GC,清除了0个
*/
3、弱引用(java.lang.ref.WeakReference)
弱引用也是用来描述一些还有用,但并非必须存在的对象,它的强度会被软引用弱些,被弱引用关联的对象,只能生存到下一次GC前,当GC工作时,无论内存是否足够,都会回收掉弱引用关联的对象。JDK通过WeakReference类来实现。
当获取时,可通过weakReference.get方法获取,可能返回null
可传入一个ReferenceQueue对象到WeakReference构造,当引用对象被表示为可回收时,isEnqueued返回true
User user = new User();
WeakReference<User> weakReference = new WeakReference<User>(user);
weakReference.get();
ReferenceQueue<User> referenceQueue = new ReferenceQueue<User>();
WeakReference<User> weakReference2 = new WeakReference<User>(user, referenceQueue);
//如被被垃圾收集器回收,则返回true
weakReference.isEnqueued();
package com.hlj.moudle.Java02垃圾收集器与内存分配策略.Jvm02引用;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
/**
* @Description
* @Author HealerJean
* @Date 2019/2/7 下午8:25.
*/
public class Jvm02WeakReference {
@SuppressWarnings({ "rawtypes", "unchecked" })
public static void main(String[] args) throws InterruptedException {
//创建弱引用
ReferenceQueue<WeakReference<G>> rq = new ReferenceQueue<WeakReference<G>>();
WeakReference[] srArr = new WeakReference[1000];
for(int i = 0; i < srArr.length; i++){
srArr[i] = new WeakReference(new G(), rq);
}
//获取被清除部分
int n=0;
for(int i = 0; i < srArr.length; i++){
if(srArr[i].isEnqueued()){
srArr[i]=null;
n++;
}
}
System.out.println("第一次GC,清除了"+n+"个");
//尝试请求一次GC,防止上面不执行垃圾收集器
System.gc();
//获取第二次被清除部分
int m=0;
for(int i = 0; i < srArr.length; i++){
if(srArr[i]!=null&&srArr[i].isEnqueued()){
srArr[i]=null;
m++;
}
}
System.out.println("第一次GC,清除了"+m+"个");
}
}
/*
output (第二次清除个数有明显变动)
第一次GC,清除了965个
第一次GC,清除了16个
*/
4、虚引用(PhantomReference)
虚引用与前面三种引用不同,并不是为了程序员干预对象的GC优先级。而是为了更精细的控制对象内存的释放,
必须与引用队列一同使用,当对象引用被释放时,其对象仍存在内存中,并未被释放,对象此时加入队列中,等待执行finalize函数。同时我们需要重写对象的finalize函数,帮助其释放内存。
虚引用称为“幻影引用”,它是最弱的一种引用关系,一个对象是否有虚引用的存在,完全不会对生存时间构成影响 。为一个对象设置虚引用关联的唯一目的就是希望能在这个对象被GC回收时收到一个系统通知。。通过PhantomReference类实现。
值得注意的是:phantomReference.get方法永远返回null, 当user从内存中删除时,调用isEnqueued会返回true
User user = new User();
ReferenceQueue<User> referenceQueue = new ReferenceQueue<User>();
PhantomReference<User> phantomReference = new PhantomReference<User>(user, referenceQueue);
//即当user对象标识为可回收时,返回true
System.out.println(phantomReference.isEnqueued());
//永远返回null
System.out.println(phantomReference.get())
package com.hlj.moudle.Java02垃圾收集器与内存分配策略.Jvm02引用;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
/**
* @Description
* @Author HealerJean
* @Date 2019/2/7 下午8:29.
*/
public class Jvm03PhantomReference {
@SuppressWarnings({ "rawtypes", "unchecked" })
public static void main(String[] args) throws InterruptedException {
//创建弱引用
ReferenceQueue<PhantomReference<G3>> rq = new ReferenceQueue<PhantomReference<G3>>();
PhantomReference[] srArr = new PhantomReference[1000];
for(int i = 0; i < srArr.length; i++){
G3 g=new G3();
srArr[i] = new PhantomReference(g, rq);
//g = null;
}
//获取被清除部分
int n = 0;
for(int i = 0; i < srArr.length; i++){
if(srArr[i].isEnqueued()){
srArr[i] = null;
n++;
}
}
System.out.println("清除了"+n+"个");
}
}
//为了占据内存
class G3{
private int [] big=new int[1000000];
@Override
protected void finalize() throws Throwable {
super.finalize();
big=null;
}
}
/*
output
清除了826个
*/