jdk1.2之前,每个对象在堆中都有一个引用计数属性,引用新增1次则计数加1,引用每释放一次则计数减一,判断对象是否可以回收的条件是对象是否可达状态;如果可达则表示对象不可回收,如果不可达就是可以回收状态;
jdk1.2之后,为了更好的控制堆中对象的生命周期,将对象分成了强引用、软引用、弱引用以及虚引用。
一、概念
1、强引用: 垃圾回收器绝对不会回收强引用,即使内存不足,宁愿抛出outOfMemoryError;
Object object = new Object();
除非主动将对象设置为null(全局参数的过程中),或者该对象超出看该对象的生命周期(方法中对象,如下:),才可以使垃圾回收器回收该对象;
public void test(){
Object object = new Object();
}
首先对象的引用在方法栈中,而该对象引用的内容在堆中,当退出方法栈,对象无引用,从而GC回收,但是当该对象是全局参数就需要主动将对象设置为null。
2、软引用: 当对象是软引用时,内存充足的情况下是不会回收该对象,但当内存不足会主动回收软引用对象,释放内存;
用来缓存,当内存不足会自动回收释放;
使用场景:可以将一些访问频繁的数据放在软引用中,直到内存不足的情况下重新从数据库中获取;
3、弱引用: 当对象为弱引用时,当垃圾回收器收集对象的时候会回收弱引用对象;
和软引用的区别在于:软引用在内存不足的情况才会回收,但弱引用对象在垃圾回收的时候就会被回收。
使用场景:其中ThreadLocal源码中就使用了弱引用,就是为了防止线程积累过多而导致内存不足,
其中ThreadLocal存储数据是为了保证每个线程都是独立的一个数据副本,从而可以在当前线程任何地方获取, 不需要通过方法参数传来传去,但是ThreadLocal不能解决父子线程数据之间的传递,每个线程数据都是独立的副本,但有时候需要在子线程中获取父线程的变量值,那么InheritableThreadLocal类就是为了解决父类线程数据副本传递到子线程的过程,是引用传递,子线程引用的值改变,父线程引用的值也改变,但是InheritableThreadLocal在线程池中不能将父线程数据传递到子线程,是因为线程池获取线程过程中不是主动new Thread线程,new Thread的过程中会将父线程副本传递给对应的子线程,线程池获取线程不一样,是一堆已经创建好的线程中获取,但有时候需要根据父线程的副本传递给线程池中某个子线程,那么阿里巴巴开发的TransmittableThreadLocal类就很好的解决了线程池父子线程副本数据的传递。
4、虚引用: 在任何时候都会被垃圾回收器回收。
二、代码
@Data
public class Role {
private String name = "role";
/**
* 弱:WeakReference.java,每次GC都会被回收;
*/
public static void weakReference() {
Role role = new Role();
WeakReference<Role> roleWeakReference = new WeakReference<>(new Role());
System.gc();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(role==null){
System.out.println("强引用对象role已经被回收!");
}
if(roleWeakReference.get() == null){
System.out.println("弱引用对象roleWeakReference 已经被回收!");
}
} /**
* 软引用:softReference.java,每次GC都会被回收;
*/
public static void softReference() {
Role role = new Role();
SoftReference<Role> softReference = new SoftReference<>(new Role());
System.gc();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(role==null){
System.out.println("强引用对象role已经被回收!");
}
if(softReference.get() == null){
System.out.println("软引用对象roleWeakReference 已经被回收!");
}else{
System.out.println("软引用对象值还存在:"+softReference.get());
}
}
/**
* 注:软引用和弱引用的区别是:软引用是需要等内存不够才回收,system.gc只是起到通知垃圾回收的作用,
* 而且当JVM垃圾回收器在内存不足的情况下回收软引用对象时,会根据引用队列的顺序先回收老对象;
* 而弱引用system.gc通知后,会安排回收
* @param args
*/
public static void main(String[] args) {
// weakReference();
//
// /**
// * 弱引用 队列使用
// */
// weakReferenceQueue();
//
// System.out.println("=============================================");
//
//
// softReference();
// /**
// * 软引用队列使用
// */
// softReferenceQueue();
//
//
System.out.println("=============================================");
/**
* 虚引用队列,虚引用必须和引用队列使用;
*/
phantomReferenceQueue();
}
private static void phantomReferenceQueue () {
ReferenceQueue<Role> reference = new ReferenceQueue();
PhantomReference<Role> phantomReference = new PhantomReference<>(new Role(),reference);
Reference<? extends Role> poll = reference.poll();
if(poll !=null){
System.out.println("gc回收之前引用队列有值");
}
System.gc();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
Reference<? extends Role> poll2 = reference.poll();
if(poll2 !=null){
System.out.println("gc回收之后引用队列有值");
}
if(phantomReference.get() == null){
System.out.println("虚引用对象phantomReference已经被回收!");
}
}
private static void softReferenceQueue() {
Role role = new Role();
ReferenceQueue<Role> reference = new ReferenceQueue();
SoftReference<Role> roleSoftReference = new SoftReference<>(new Role(),reference);
Reference<? extends Role> poll = reference.poll();
if(poll !=null){
System.out.println("gc回收之前引用队列有值");
}
System.gc();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
Reference<? extends Role> poll2 = reference.poll();
if(poll2 !=null){
System.out.println("gc回收之后引用队列有值");
}
if(role==null){
System.out.println("强引用对象role已经被回收!");
}
if(roleSoftReference.get() == null){
System.out.println("软引用对象roleSoftReference已经被回收!");
}
}