强软弱虚
java中的数据被类型分为了两类,它们分别是基本类型和引用类型。一般我们new出来的对象都属于引用类型的范畴。我们知道java是有垃圾回收机制的一种语言,根据垃圾回收时的策略,java将对于堆对象的引用又进行了细分,引用被分为了强引用,软引用,弱引用和虚引用。
强引用
强引用又称普通引用,它是最常见的一种引用类型,一般我们通过new关键字创建对象时,变量对于堆对象的引用就是强引用。
强引用的特点:
如果堆中的一个对象被强引用指向,那么这个变量将不会被GC回收。
在堆内存不够用的情况下,被强引用指向的对象也不会被回收。(宁可抛出OOM异常)
被强引用指向的对象,只有在引用消失后才会被GC回收。
测试代码-1:
1 /*这个类用于申请堆内存*/
2 public classMemory {3 private byte[] alloc;4
5 public Memory(int size) { this.alloc = new byte[size]; }6
7 @Override8 protected voidfinalize() throws Throwable {9 super.finalize();10 System.out.println("被GC回收");11 }12 }
1 public classNormal {2 public static void main(String[] args) throwsInterruptedException {3
4 /*栈变量m对new出来的Memory对象的引用为强引用*/
5 Memory m = new Memory(1024 * 1024 * 20);6
7 /*现在堆中的对象没有引用指向它,它要被GC回收*/
8 m = null;9
10 System.gc(); /*显式GC*/
11
12 /*
13 * 当我们启动java程序时,默认会有两个线程,一个是我们的主线程,另一个便是GC线程。14 * 通常GC线程的优先级比较低,并且GC线程默认为守护线程,即它会在主线程退出的同15 * 时退出。16 *17 * 为了观察到GC的效果,我们让主线程休眠1s18 */
19 Thread.sleep(1000);20 }21
22 }
测试结果-1:
测试代码-2
1 public classNormal {2
3 public static void main(String[] args) throwsInterruptedException {4
5 /*我们设定JVM参数,设置堆内存大小为25MB*/
6
7
8 /*栈变量m1对new出来的Memory对象的引用为强引用*/
9
10 /*申请了20MB的内存,实际会大于20MB,因为我们的byte[]被Memory对象wrapper*/
11 Memory m1 = new Memory(1024 * 1024 * 20);12
13 System.gc();14 Thread.sleep(1000);15
16 /*再申请10MB堆内存*/
17 Memory m2 = new Memory(1024 * 1024 * 10);18 }19
20 }
测试结果-2
软引用
软引用的创建需要借助jdk中java.lang.ref.SoftReference这个类来创建。也就是说,我们的变量是先引用到SoftReference这个对象,SofReference这个对象再去引用我们想要设置为软引用的对象。
软引用的特点
当堆内存够用时,被软引用指向的对象不会被GC回收。
当堆内存不够用时,被软引用指向的对象自动的被GC回收。
测试代码-3
1 public classSoft_Ref {2
3 public static void main(String[] args) throwsInterruptedException {4 /*堆内存大小为50MB*/
5 /*申请30MB*/
6 SoftReference m1 = new SoftReference<>(new Memory(1024 * 1024 * 30));7
8 System.gc(); /*显示调用GC*/
9
10 /*此时内存够用,所以结果可以预见性的为GC不会回收被软引用指向的对象*/
11
12 Thread.sleep(1000);13 }14 }
测试结果-3
测试代码-4
1 public classSoft_Ref {2 public static void main(String[] args) throwsInterruptedException {3
4 /*堆内存大小为50MB*/
5
6 /*申请30MB*/
7 SoftReference m1 = new SoftReference<>(new Memory(1024 * 1024 * 30));8
9
10 /*申请20MB*/
11 for (int i = 0; i < 20; ++i) {12 System.out.println("[time] => " +System.currentTimeMillis());13 SoftReference ma = new SoftReference<>(new Memory(1024 * 1024));14 Thread.sleep(200);15 }16 }17 }
测试结果-4
从测试结果可以看出,当内存不够用或者将要不够用时,会触发GC,GC会自动的回收那些软引用指向对象。
一定要注意,软引用指向对象的回收是在触发GC的条件下才会被回收,如果内存够用,就算显式的调用GC,软引用指向的对象也不会被回收。
弱引用
弱引用的创建方式与软引用类似,需要借助于jdk中java.lang.ref.WeakReference类去创建。
弱引用的特点:
不管什么情况,遇到GC就会回收被弱引用指向的对象。
测试代码-5
1 public classWeak_Ref {2
3 public static void main(String[] args) throwsInterruptedException {4 /*堆内存没有设置大小,为默认状态*/
5 WeakReference m = new WeakReference<>(new Memory(1024 * 1024 * 10));6 System.gc(); /*调用GC*/
7 Thread.sleep(1000);8 }9 }
测试结果-5
虚引用
虚引用是一种十分特殊的引用,它主要用在堆外内存的管理,虚引用可以指向堆中的对象,但是没有实际的意义。
虚引用的特点:
无法获取虚引用指向的对象的值。
虚引用在被GC回收时会有通知。
虚引用在遇到GC时,不管是否还有对象引用它,它都会被GC回收。
测试代码-6
1 public classPhantom_Ref {2 static final ArrayList LIST = new ArrayList<>();3
4 static final ReferenceQueue QUEUE = new ReferenceQueue<>();5
6 public static void main(String[] args) throwsInterruptedException {7
8 PhantomReference m = new PhantomReference<>(new Memory(1024 * 1024 * 10), QUEUE);9 new Thread(()->{10 while (true) {11 LIST.add(new byte[1024 * 1024]);12
13 try{14 Thread.sleep(1000);15 } catch(InterruptedException e) {16 e.printStackTrace();17 Thread.currentThread().interrupt();18 }19 System.out.println(m.get()); /*虚引用指向的值永远无法被获取*/
20 }21 }).start();22
23 new Thread(()->{24 while (true) {25 Reference extends Memory> poll =QUEUE.poll();26 if (poll != null) {27 /*虚引用在对象回收时,会进行通知*/
28 System.out.println("有虚引用被GC回收了-" +poll);29 break;30 }31 }32 }).start();33 }34 }
测试结果-6
以上就是小编整理的Java的四种引用,只是个人的一些理解看法,有哪里不准确的地方,还请大家多多指出,小编和大家共同进步!!!
喜欢文章请多多点赞评论转发,关注小编,你们的支持就是小编创作的无限动力!!!!!