- 强引用对象是不可以被垃圾回收的,很容易由于代码 不规范产生内存溢出
比如创建了很多对象,压入栈中,后来只是弹出了对象,而没有手动销毁,这样就会内存泄漏,就是引用仍然存在,但是代码逻辑上访问不到了- 终结强引用,就是把当前变量指向null,断开栈和堆空间的联系
public class StrongReferenceTest {
public static void main(String[] args) {
StringBuffer str = new StringBuffer ("Hello");
StringBuffer str1 = str;
str = null;
System.gc();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(str1);//str1虽然通过null指向空了,但是str1和他还有联系,所以不会被回收
}
}
public class StrongReferenceTest {
public static void main(String[] args) {
StringBuffer str = new StringBuffer ("Hello,尚硅谷");
System.gc();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(str);//仍然没有被回收。因为在方法栈中被引用了
}
}
软引用的对象会在第一次垃圾回收的时候记录,等第一次垃圾回收后发现内存不够才会对软引用做回收
package src.Tjvm.Yinyong;
import java.lang.ref.SoftReference;
/**
* 软引用的测试:内存不足即回收
*
* @author shkstart shkstart@126.com
* @create 2020 16:06
*/
public class SoftReferenceTest {
public static class User {
public User(int id, String name) {
this.id = id;
this.name = name;
}
public int id;
public String name;
@Override
public String toString() {
return "[id=" + id + ", name=" + name + "] ";
}
}
public static void main(String[] args) {
//创建对象,建立软引用
// SoftReference userSoftRef = new SoftReference(new User(1, "songhk"));
//上面的一行代码,等价于如下的三行代码
User u1 = new User(1,"songhk");
SoftReference<User> userSoftRef = new SoftReference<User>(u1);
u1 = null;//取消强引用
//从软引用中重新获得强引用对象
System.out.println(userSoftRef.get());
System.gc();
System.out.println("After GC:");
// //垃圾回收之后获得软引用中的对象
System.out.println(userSoftRef.get());//由于堆空间内存足够,所有不会回收软引用的可达对象。
//
try {
//让系统认为内存资源紧张、不够
byte[] b = new byte[1024 * 1024 * 7];
//byte[] b = new byte[1024 * 7168 - 635 * 1024];
} catch (Throwable e) {
e.printStackTrace();
} finally {
//再次从软引用中获取数据
System.out.println(userSoftRef.get());//在报OOM之前,垃圾回收器会回收软引用的可达对象。
}
}
}
-Xmx7m JVM参数
第一次垃圾回收就会进行回收
*/
public class WeakReferenceTest {
public static class User {
public User(int id, String name) {
this.id = id;
this.name = name;
}
public int id;
public String name;
@Override
public String toString() {
return "[id=" + id + ", name=" + name + "] ";
}
}
public static void main(String[] args) {
//构造了弱引用
WeakReference<User> userWeakRef = new WeakReference<User>(new User(1, "songhk"));
//从弱引用中重新获取对象
System.out.println(userWeakRef.get());
System.gc();
// 不管当前内存空间足够与否,都会回收它的内存
System.out.println("After GC:");
//重新尝试从弱引用中获取对象
System.out.println(userWeakRef.get());
}
}
weakhashmap 就是一个弱引用的HaspMap,里面存放的对象都是弱引用对象,当内存不足的时候可以释放
虚引用在垃圾回收的时候也会被回收,唯一的不同就是回收的对象会被放到一个自定义的队列里先,从而获得对这个对象被回收的通知
public class PhantomReferenceTest {
public static PhantomReferenceTest obj;//当前类对象的声明
static ReferenceQueue<PhantomReferenceTest> phantomQueue = null;//引用队列
public static class CheckRefQueue extends Thread {
@Override
public void run() {
while (true) {
if (phantomQueue != null) {
PhantomReference<PhantomReferenceTest> objt = null;
try {
objt = (PhantomReference<PhantomReferenceTest>) phantomQueue.remove();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (objt != null) {
System.out.println("追踪垃圾回收过程:PhantomReferenceTest实例被GC了");
}
}
}
}
}
@Override
protected void finalize() throws Throwable { //finalize()方法只能被调用一次!
super.finalize();
System.out.println("调用当前类的finalize()方法");
obj = this;
}
public static void main(String[] args) {
Thread t = new CheckRefQueue();
t.setDaemon(true);//设置为守护线程:当程序中没有非守护线程时,守护线程也就执行结束。
t.start();
phantomQueue = new ReferenceQueue<PhantomReferenceTest>();
obj = new PhantomReferenceTest();
//构造了 PhantomReferenceTest 对象的虚引用,并指定了引用队列
PhantomReference<PhantomReferenceTest> phantomRef = new PhantomReference<PhantomReferenceTest>(obj, phantomQueue);
try {
//不可获取虚引用中的对象
System.out.println(phantomRef.get());
//将强引用去除
obj = null;
//第一次进行GC,由于对象可复活,GC无法回收该对象
System.gc();
Thread.sleep(1000);
if (obj == null) {
System.out.println("obj 是 null");
} else {
System.out.println("obj 可用");
}
System.out.println("第 2 次 gc");
obj = null;
System.gc(); //一旦将obj对象回收,就会将此虚引用存放到引用队列中。
Thread.sleep(1000);
if (obj == null) {
System.out.println("obj 是 null");
} else {
System.out.println("obj 可用");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
终结器引用和虚引用类似,可以把回收的对象放到队列,不同的是这个终结器可以自动开启一个线程依次调用对象的finilaze方法试图复活对象。