继承关系图
强引用
定义:
强引用(系统默认):当内存不足是,JVM开始垃圾回收,对于强引用的对象,就算是出现了OOM也不会对该对象进行回收
最常见的强引用:把一个对象赋给一个引用对象,这个引用对象就是强引用。当一个对象被强引用变量引用时,它是处于可达状态,它是不可能被垃圾回收机制回收的。
实例:
package com.example.demo.Reference;
import com.example.demo.entity.DateDemo;
/**
* 强引用类型
*/
public class StrongRederenceDemo {
public static void main(String[] args) {
//这样定义默认强引用
DateDemo dateDemo = new DateDemo();
//进行引用赋值 dateDemo1 也是强引用
DateDemo dateDemo1 = dateDemo;
//进行置空
dateDemo = null ;
//手动垃圾回收
System.gc();
System.out.println(dateDemo1);
}
}
显示效果:强引用不会被回收
DateDemo{name='null', date=null}
软引用:
定义:
软引用:是相对于强引用弱一点的引用,需要使用java.lang.ref.SoftReference来实现,内存足够的情况下不会进行垃圾回收,当内存足够的情况下会被回收。
使用场景:
场景一:
软引用通常用在对内存敏感的程序中,比如高速缓存就会用到软引用,内存够用的时候就保留,不够的时候就回收。Mybatis底层用了SoftReference
场景二:
一个应用需要读取大量图片的时候:
1.每次都从硬盘里面读取信息,可能会严重影响系统性能。
2.如果一次性全部读取到内存,可能会导致内存的溢出。
可以使用软引用解决这个问题
设计思路:
可以创建一个hashMap来存取图片的URL和相关图片关联的软引用之间的映射关系,内存不足的时候,会自动回收软引用的内存空间,从而有效避免OOM的问题。
实例:内存够用的情况
package com.example.demo.Reference;
import java.lang.ref.SoftReference;
/**
* 软引用
* 内存够用就保留,内存不够就回收
*/
public class SoftReferenceDemo {
public static void main(String[] args) {
//object是强引用
Object object = new Object();
SoftReference<Object> softReference = new SoftReference<Object>(object);
//获取软引用对象
Object softObject = softReference.get();
System.out.println(object);
System.out.println(softObject);
//赋值为null 手动gc
object = null;
System.gc();
System.out.println("=============分割线=======================");
//查看软引用是否有值
System.out.println(object);
System.out.println(softObject);
}
}
显示效果:软引用对象不会被回收
java.lang.Object@129a8472
java.lang.Object@129a8472
=============分割线=======================
null
java.lang.Object@129a8472
实例二:内存不够,软引用回收,这里的软引用对象为softReference.get()产生的对象,如果给一个引用赋值,就是强引用。
/**
* 在 Run -> edit configuration 配置jvm参数
* 通过设置JVM参数设置小的内存空间
* -Xmx5m -Xms5m -XX:+PrintGCDetails
*/
private static void NoSpaceRunSoftReference() {
//object是强引用
Object object = new Object();
SoftReference<Object> softReference = new SoftReference<>(object);
//注意softObject为强引用对象
// Object softObject = softReference.get();
//获取软引用对象
System.out.println(object);
System.out.println(softReference.get());
object = null;
try {
//创建一个字节数组把内存撑爆
byte[] bytes = new byte[35 * 1024 * 1024];
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println("=============分割线=======================");
System.out.println("强引用对象:"+object);
System.out.println("弱引用对象:"+softReference.get());
}
}
显示效果:内存不够,软引用被回收
=============分割线=======================
强引用对象:null
弱引用对象:null
Heap
PSYoungGen total 1536K, used 68K [0x00000000ffe00000, 0x0000000100000000, 0x0000000100000000)
eden space 1024K, 6% used [0x00000000ffe00000,0x00000000ffe110c0,0x00000000fff00000)
from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
to space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
ParOldGen total 4096K, used 1577K [0x00000000ffa00000, 0x00000000ffe00000, 0x00000000ffe00000)
object space 4096K, 38% used [0x00000000ffa00000,0x00000000ffb8a408,0x00000000ffe00000)
Metaspace used 3577K, capacity 4500K, committed 4864K, reserved 1056768K
class space used 385K, capacity 388K, committed 512K, reserved 1048576K
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.example.demo.Reference.SoftReferenceDemo.NoSpaceRunSoftReference(SoftReferenceDemo.java:29)
at com.example.demo.Reference.SoftReferenceDemo.main(SoftReferenceDemo.java:12)
弱引用
定义:
不管JVM内存是否够,只要gc,内存就会被回收。需要使用java.lang.ref.WeakReference来实现,它比软引用的生命周期更短。
适用场景:
大量图片的读取问题,可能会导致性能降低或者OOM的问题
实例一:
package com.example.demo.Reference;
import java.lang.ref.WeakReference;
/**
* 弱引用
*/
public class WeakReferenceDemo {
public static void main(String[] args) {
//创建一个强引用
Object object = new Object();
//new弱引用类 来获取弱引用对象
WeakReference<Object> weakReference = new WeakReference<>(object);
//先行打印两个对象
System.out.println(object);
System.out.println(weakReference.get());
//手动gc 并且给 object赋值
object = null;
System.gc();
System.out.println("=============分割线================");
System.out.println(object);
System.out.println(weakReference.get());
}
}
展示结果:
java.lang.Object@129a8472
java.lang.Object@129a8472
=============分割线================
null
null
虚引用:
定义:
需要使用java.lang.ref.PlantomReference类来实现。
如果一个对象仅持有虚引用,那么她就和没有引用是一样的,在任何时候都可能被垃圾回收器回收,它不能单独使用也不能通过它来访问对象,需要必须和引用队列(ReferenceQueue)联合使用
gc之后会先放到ReferenceQueue里面
适用场景:
主要作用是跟踪对象被垃圾回收的状态。仅仅是提供了一种确保对象被finalize以后,做某些事情的机制。
PhantomReference的get方法总是返回null,因此无法访问对应的引用对象。其意义在于说明一个对象已经进入finalization阶段,可以被ac回收,用来实现比finalization机制更灵活的回收操作。
实例:
package com.example.demo.Reference;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.util.concurrent.TimeUnit;
/**
* 虚引用
* 使用的是PhantomReference 必须与ReferenceQueue队列一起使用 一般不会使用
*/
public class PhantomReferenceDemo {
public static void main(String[] args) {
//创建引用队列
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
Object object = new Object();
//初始化的时候会把引用队列里面添加到引用类里面
PhantomReference<Object> phantomReference = new PhantomReference<>(object, referenceQueue);
System.out.println("object强引用:"+object);
System.out.println("phantomReference弱引用:"+phantomReference.get());
System.out.println("referenceQueue队列里面的数据:"+referenceQueue.poll());
//object 赋值为null
object = null;
//手动gc
System.gc();
//保证gc完全执行成功
try {
TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
//查看gc之后的结果
System.out.println("===========================================");
System.out.println("object强引用gc之后:"+object);
System.out.println("phantomReference弱引用gc之后:"+phantomReference.get());
System.out.println("referenceQueue队列里面的数据gc之后:"+referenceQueue.poll());
}
}
显示结果
object强引用:java.lang.Object@129a8472
phantomReference弱引用:null
referenceQueue队列里面的数据:null
===========================================
object强引用gc之后:null
phantomReference弱引用gc之后:null
referenceQueue队列里面的数据gc之后:java.lang.ref.PhantomReference@1b0375b3
课后拓展:WeakHashMap,当gc后,内存全部会被回收
package com.example.demo.Reference;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.WeakHashMap;
/**
* WeakHashMap的测试
* 缓存清空,有效避免OOM问题,和保证性能的问题
* 针对与大量的读取图片的问题
* 一个应用需要读取大量图片的时候:
* 1.每次都从硬盘里面读取信息,可能会严重影响系统性能。
* 2.如果一次性全部读取到内存,可能会导致内存的溢出。可以使用软/弱引用解决这个问题
*/
public class WeakHashMapDemo {
/**
* HashMap 当gc后,键值都会被保留
* WeakHsahMap 当gc后,所有的键值对的内存都会被清空
* @param args
*/
public static void main(String[] args) {
HashMap<Integer, String> hashMap = new HashMap<>();
Integer key = new Integer(1);
hashMap.put(key,"添加到hashmap的值");
//给key赋值为null
key = null;
System.out.println("key为null状态下的hashmap:"+hashMap);
//手动gc
System.gc();
System.out.println("gc后key为null状态下的hashmap:"+hashMap);
System.out.println("================================");
WeakHashMap<Integer, String> weakHashMap = new WeakHashMap<>();
Integer weakKey = new Integer(2);
weakHashMap.put(weakKey,"添加到weakHashMap的值");
weakHashMap.put(new Integer(3),"弱引用");
//给weakKey赋值为null
weakKey = null;
System.out.println("weakKey为null状态下的weakHashMap的值:"+weakHashMap);
//手动gc
System.gc();
System.out.println("gc后weakKey为null状态下的weakHashMap的值:"+weakHashMap);
}
}
展示结果:
key为null状态下的hashmap:{1=添加到hashmap的值}
gc后key为null状态下的hashmap:{1=添加到hashmap的值}
================================
weakKey为null状态下的weakHashMap的值:{3=弱引用, 2=添加到weakHashMap的值}
gc后weakKey为null状态下的weakHashMap的值:{}
扩展2:引用队列:gc之后的对象会装入到引用队列里面,在初始化引用类的时候传入相应的引用队列
package com.example.demo.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.concurrent.TimeUnit;
/**
* 引用队列
* gc之后的引用对象会添加到引用队列里面
*/
public class ReferenceQueueDemo {
public static void main(String[] args) {
//创建引用队列
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
Object object = new Object();
//初始化的时候会把引用队列里面添加到引用类里面
WeakReference<Object> objectWeakReference = new WeakReference<>(object, referenceQueue);
System.out.println("object强引用:"+object);
System.out.println("objectWeakReference弱引用:"+objectWeakReference.get());
System.out.println("referenceQueue队列里面的数据:"+referenceQueue.poll());
//object 赋值为null
object = null;
//手动gc
System.gc();
//保证gc完全执行成功
try {TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
//查看gc之后的结果
System.out.println("===========================================");
System.out.println("object强引用gc之后:"+object);
System.out.println("objectWeakReference弱引用gc之后:"+objectWeakReference.get());
System.out.println("referenceQueue队列里面的数据gc之后:"+referenceQueue.poll());
}
}
展示结果:
object强引用:java.lang.Object@129a8472
objectWeakReference弱引用:java.lang.Object@129a8472
referenceQueue队列里面的数据:null
===========================================
object强引用gc之后:null
objectWeakReference弱引用gc之后:null
referenceQueue队列里面的数据gc之后:java.lang.ref.WeakReference@1b0375b3