2019独角兽企业重金招聘Python工程师标准>>>
1. 引用类型划分
-
强引用:当内存不足时,JVM宁可出现“OutOfMemoryError”错误停止,也需要进行保存,并且不会将此空间回收。
-
软引用:当内存不足的时候,进行对象的回收处理,往往用于高速缓存中。
-
弱引用:不管内存是否紧张,只要有垃圾产生,立即回收。
-
幽灵引用(虚引用):和没有引用是一样的。
2. 强引用
1. 简单介绍
- 强引用是JVM默认的支持模式,即:在引用的期间内,如果该堆内存被指定的栈内存有联系,那么该对象就无法被GC所回收,而一旦出现内存空间不足,就会出现“OutOfMemoryError”。
2. 范例:观察强引用
-
测试代码
public class TestDemo {public static void main(String[] args) {Object obj = new Object(); // 强引用,默认的支持Object ref = obj; // 引用传递obj = null; // 断开了一个连接System.gc();System.out.println(ref);} }
-
终端命令
> javac TestDemo.java > java TestDemo
-
结果
java.lang.Object@15db9742
-
结论
- 此时如果对象堆内存有栈内存的指向,那么该对象将无法被GC回收。
- 强引用是我们一直在使用的模式,并且也是以后的开发中主要的使用模式,因为强引用有这样的内存分配异常问题,所以开发原则是尽量少实例化对象。
3. 软引用
1. 简单介绍
-
在很多的开源组件之中,往往会使用软引用作为缓存组件出现,其最大的特点:内存不足时回收,充足时不回收。
-
想实现软引用需要单独的一个类来实现控制:java.lang.ref.SoftReference
2. 范例:观察软引用
-
测试代码:
import java.lang.ref.SoftReference;public class TestDemo {public static void main(String[] args) {Object obj = new Object();SoftReference<Object> ref = new SoftReference<Object>(obj); // 软引用obj = null; // 断开连接System.gc();System.out.println(ref.get());} }
-
终端命令
> javac TestDemo.java > java TestDemo
-
结果
java.lang.Object@15db9742
-
结论
- 软引用在内存不紧张的情况下不会被回收。
3. 范例:观察内存紧张情况下的软引用
-
测试代码
import java.lang.ref.SoftReference;public class TestDemo {public static void main(String[] args) {Object obj = new Object();String str = "hello world !!!";SoftReference<Object> ref = new SoftReference<Object>(obj);obj = null;try {for (int i = 0; i < 10000; i++) {str += str;str.intern();}} catch (Throwable e) {}System.gc();System.out.println(ref.get());} }
-
终端命令
> javac TestDemo.java > java -Xmx10m -Xms10m TestDemo
-
结果
null
-
结论
- 软引用在内存紧张的情况下会被回收。
4. 弱引用
1. 简单介绍
- 弱引用,只要一进行gc处理,那么所引用的对象将会立即被回收。弱引用需要使用的是Map接口的子类:java.util.WeakHashMap。
2. 范例:观察弱引用
-
测试代码
import java.lang.ref.SoftReference; import java.util.Map; import java.util.WeakHashMap;public class TestDemo {public static void main(String[] args) {String key = new String("shadowolf");String value = new String("www.shadowolf.cn");Map<String, String> map = new WeakHashMap<String, String>();map.put(key, value);System.out.println(map);key = null;System.out.println(map);System.gc();System.out.println(map);} }
-
终端命令
> javac TestDemo.java > java TestDemo
-
结果
{shadowolf=www.shadowolf.cn} {shadowolf=www.shadowolf.cn} {}
-
结论
- 一旦出现GC,则必须进行回收处理,并且一回收一个准。
3. 范例:观察 java.lang.ref.WeakReference
-
测试代码
import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.util.Map; import java.util.WeakHashMap;public class TestDemo {public static void main(String[] args) {String key = new String("shadowolf");WeakReference<String> ref = new WeakReference<String>(key);System.out.println(ref.get());key = null;System.out.println(ref.get());System.gc();System.out.println(ref.get());} }
-
终端命令
> javac TestDemo.java > java TestDemo
-
结果
shadowolf shadowolf null
5. 引用队列
1. 简单介绍
- 引用队列保存那些准备被回收的对象。很多时候所有的对象的回收扫描都是从根对象开始的,那么对于整个GC而言,如果要想确定哪些对象可以被回收,就必须确定好引用的强度,这个也就是所谓的引用路径的设置。
2. 引用队列的操作流程
-
单条引用路径的可及性判断:在这条路径上,最弱的一个引用决定对象的可及性。
-
多条引用路径的可及性判断:在这几条路径上,最强的一个引用决定对象的可及性。
-
例如:如果要找到对象5,那么1找到5属于“强 + 软”,2找到5属于“强 + 弱”。软引用比弱引用保存的强。所以这个时候对于对象的引用而言,如果要进行引用关联的判断,那么就必须找到强关联,为了避免非强引用对象所带来的内存引用问题,所以提供引用队列的概念。如果在创建一个软引用或弱引用对象使用了引用队列的方式,那么这个对象在回收之后会自动保存到引用队列之中。
3. 范例:使用引用队列
-
测试代码
import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference;public class TestDemo {public static void main(String[] args) throws Exception {Object obj = new Object();ReferenceQueue<Object> queue = new ReferenceQueue<Object>();WeakReference<Object> ref =new WeakReference<Object>(obj, queue);System.out.println(queue.poll());obj = null;System.gc();Thread.sleep(100); // 保存引用队列需要点时间System.out.println(queue.poll());} }
-
终端命令
> javac TestDemo.java > java TestDemo
-
结果
null java.lang.ref.WeakReference@15db9742
-
结论
- 被回收的弱引用对象被保存到了引用队列中。
- 引用队列主要做一些被回收对象的控制。
6. 幽灵引用(虚引用)
1. 简单介绍
- 永远取得不了的数据就叫幽灵引用。
2. 范例:观察幽灵引用
-
测试代码
import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue;public class TestDemo {public static void main(String[] args) throws Exception {Object obj = new Object();ReferenceQueue<Object> queue = new ReferenceQueue<Object>();PhantomReference<Object> ref = new PhantomReference<Object>(obj, queue);System.gc();System.out.println(ref.get());System.out.println(queue.poll());} }
-
终端命令
> javac TestDemo.java > java TestDemo
-
结果
null null
-
结论
- 所有保存在幽灵引用类型中的数据都不会真正的保留。