Java中的4中引用的差别和使用场景
一、强引用
-
特点
- 强引用不会被GC回收,当前内存不足的时候,JVM宁愿抛出java.lang.OutOfMemoryError: Java heap space让程序假死,也不会随意去回收具有强引用的对象
- 常见的强引用:把一个对象赋给引用变量,这个引用变量就是一个强引用,如果在不使用这个变量的时候,将这变量强制为null,可以被gc掉
-
代码:
/** * @Author yixiangfeng * @ClassName StrongRef * @Description 强引用 * @CreateTime 下午2:34 **/ public class StrongRef { public static class User { private Integer userId; private String userName; public User(Integer userId,String userName) { this.userId = userId; this.userName = userName; } @Override public String toString() { return "User{" + "userId=" + userId + ", userName='" + userName + '\'' + '}'; } } public static void main(String[] args) { User user = new User(1, "zhaoliu"); User strongUser = user; System.out.println("Before GC"); System.out.println(user); user = null; System.gc(); System.out.println("After GC"); System.out.println(strongUser); } }
二、弱引用
-
特点:
- 弱引用需要用WeakReference类来实现。比软引用的生存期更短,对于只有弱引用的对象。只要垃圾回收机制一运行,不管JVM的内存空间是否足够。总会回收该对象占用的内存
- Weak引用对象常用于Map数据结构中,引用占用内存空间较大的对象
-
代码:
package top.yxf.jvm; import java.lang.ref.WeakReference; /** * @Author yixiangfeng * @ClassName WeakRef * @Description 虚引用 * @CreateTime 下午5:08 **/ public class WeakRef { public static class User { private Integer userId; private String userName; public User(Integer userId,String userName) { this.userId = userId; this.userName = userName; } @Override public String toString() { return "User{" + "userId=" + userId + ", userName='" + userName + '\'' + '}'; } } public static void main(String[] args) { User user = new User(1,"zhangsan"); WeakReference<User> reference = new WeakReference<>(user); user = null; System.out.println("Before GC"); System.out.println(reference.get()); System.gc(); System.out.println("After GC"); System.out.println(reference.get()); } } ## 输出结果 Before GC User{userId=1, userName='zhangsan'} After GC null
三、软引用
-
特点
- 软引用需要用SoftReference类实现。
- 当系统内存足够时它不会被回收。
-
代码:
/** * @Author yixiangfeng * @ClassName SoftRef * @Description 软引用 * @CreateTime 上午11:47 **/ public class SoftRef { public static class User { private Integer userId; private String userName; public User(Integer userId,String userName) { this.userId = userId; this.userName = userName; } @Override public String toString() { return "User{" + "userId=" + userId + ", userName='" + userName + '\'' + '}'; } } public static void main(String[] args) { User lisi = new User(1, "lisi"); SoftReference<User> softReference = new SoftReference(lisi); System.out.println("Before gc"); System.out.println(softReference.get()); lisi = null; System.gc(); System.out.println("After gc"); System.out.println(softReference.get()); } } ## 输出结果 Before gc User{userId=1, userName='lisi'} After gc User{userId=1, userName='lisi'}
四、虚引用
-
特点
- 虚引用需要PhantomReference类实现,它不能单独使用,必须和引用队列联合使用。
- 虚引用的主要作用是跟踪对象被垃圾回收的状态。
- 主要是跟踪对象被垃圾回收的状态
-
代码:
-
PhantomReference源码:
从源码可以看出,始终获取的都是null。注释提示: Returns this reference object’s referent. Because the referent of a phantom reference is always inaccessible, this method always returns null (返回此引用对象的引用对象,因为幻想引用的引用对象始终不可访问,所以此方法始终返回的是null)
-
实现
/** * @Author yixiangfeng * @ClassName PhantomRef * @Description 虚引用 * @CreateTime 上午11:49 **/ public class PhantomRef { public static class User { private Integer userId; private String userName; public User(Integer userId,String userName) { this.userId = userId; this.userName = userName; } @Override public String toString() { return "User{" + "userId=" + userId + ", userName='" + userName + '\'' + '}'; } } public static void main(String[] args) { User wangwu = new User(1, "wangwu"); ReferenceQueue<User> queue = new ReferenceQueue<>(); PhantomReference<User> phantomReference = new PhantomReference<>(wangwu,queue); System.out.println("Before gc"); System.out.println(phantomReference.get()); System.out.println(queue.poll()); wangwu = null; System.gc(); System.out.println("After gc"); System.out.println(phantomReference.get()); System.out.println(queue.poll()); } } ## 输出结果 Before gc null After gc null
-