面试之javaSe(二)

来源:互联网 发布:ig是什么社交软件 编辑:程序博客网 时间:2024/06/05 08:08

 Java的四种引用,强弱软虚,用到的场景

java引用和java回收机制的关系

当java虚拟机(JVM)觉得内存不够的时候,会触发垃圾回收操作(GC),清除无用的对象,释放内存。可是如何判断一个对象是否为垃圾呢?其中一个办法就是计算指向该对象的数量,如果数量为零,那么该对象就是垃圾(Thread对象除外),其他的就不能回收,如果回收了这些没有被引用的对象后还是没法满足内存需求,怎么办?java把引用分位四种类型,垃圾回收器会尝试回收弱引用的对象。

按照一个对象的引用可达(Reachable)强度,有强到弱分为五大类,如下:

  • 强可达(Strong Reachable)
在一个线程内,无需引用直接可达,新创建的对象是强可达。
  • 软可达(Soft Reachable)
不是强可达。但是通过一个软引用(SoftReference)可达。
  • 弱可达(Weak Reachable)
通过弱引用(WeakReachable)可达
  • 虚可达(Phantom Reachable)
通过虚引用可达(PhantomReference)
  • 不可到达(Ureachable)
没有任何引用的对象

java回收器会优先回收可达强度较低的对象,另外两个重要的点:

  • JVM保证抛出out of memory之前,清理所有的软引用对象
  • 强可达的一定不会被清理

java中的4中引用

  • 强引用(StrongReference)

我们平时用的就是强引用,普通系统99%的以上都是强引用,比如 String  s = "dddd";  类似于必不可少的生活必须品,垃圾回收器绝对不会回收他,当内存不足时,java虚拟机宁愿抛出OutOfMemoryError,也不会回收强引用对象。强引用具有以下特征:
    强引用可以直接访问目标对象。
    强引用所指向的对象在任何时候都不会被系统回收。
    强引用可能导致内存泄漏。

  • 软引用(SoftReference)


如果一个对象具有软引用就想可有可无的生活用品,内存足够时,就不会被回收,内存不足时就会回收,只要没有回收他,改对象就可以被程序使用。软引用可以用来实现内存敏感的高速缓存。
软引用可以和一个引用队列(ReferenceQueque) 联合使用如果软引用的对象被回收了,java虚拟机就会把这个软引用加入到与之关联的引用队列中,此时并没有真正被回收,此时PhantomReference所指向的对象并没有被GC回收,而是要等到ReferenceQueue被你真正的处理后才会被回收
使用时,一般通过SoftRefrence的构造方法,将需要引用的对象封装起来,当需要时调用get()方法来获取,当对象未被回收时,SoftRefrence会返回改对象的强引用,具体如下:
Object obj = new Object();
SoftReference<Object>  softObj =  new SoftReference(obj);//获取软引用所引用的对象Object  objSoft = softObj.get();

软引用有以下特征:

   软引用使用 get() 方法取得对象的强引用从而访问目标对象。
    软引用所指向的对象按照 JVM 的使用情况(Heap 内存是否临近阈值)来决定是否回收。
    软引用可以避免 Heap 内存不足所导致的异常。

当垃圾回收器决定对其回收时,会先清空它的 SoftReference,也就是说 SoftReference 的 get() 方法将会返回 null,然后再调用对象的 finalize() 方法,并在下一轮 GC 中对其真正进行回收。

  • 弱引用(WeakReference)

弱引用和软引用类似,区别在于,只具有弱引用的对象拥有更短的生命周期,垃圾回收器线程扫描他所管辖的内存区域时,一旦发现弱引用对象不管内存空间够不够都会回收,不过垃圾回收线程优先级很低,因此不会很快发现。

弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果持有弱引用的对象呗回收了,java虚拟机就会把这个弱引用加入到与之关联的引用队列中。完全可以通过和 SoftReference 一样的方式来操作 WeakReference,这里就不再复述。

弱引用有以下特征:

    弱引用使用 get() 方法取得对象的强引用从而访问目标对象。
    一旦系统内存回收,无论内存是否紧张,弱引用指向的对象都会被回收。
    弱引用也可以避免 Heap 内存不足所导致的异常

  • 虚引用(PhantomReference)

顾名思义,就是形同虚设,与其他引用不同,虚引用不会决定对象的生命周期。如果一个对象持有虚引用,就跟没有被引用一样,随时都有可能被垃圾回收。
虚引用主要用来用来跟踪对象被垃圾回收的活动(处理资源清理的问题),虚引用跟弱引用和软引用的区别:不像软引用、弱引用会自动回收内存,虚引用的存在(虽然内存还是会被回收)更倾向于发送通知,当一个对象确定会被回收之后(此时虚引用中的引用对象并不能确定是否已经被回收内存了,而软引用和弱引用一定是被回收内存了的),就会向应用程序发送一个通知(进入队列和出队列),“我要被清理了,你们是否要做些什么事情呢?”。
  所以,虚引用用来做对象清理工作,比finalize方法再好不过了,不会导致垃圾回收器额外做工作,配合Reference阻塞方法remove就能更及时做清理工作。
Object obj = new Object();ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();PhantomReference<Object> phanRef = new PhantomReference<Object>(obj, refQueue);// 调用phanRef.get()不管在什么情况下会一直返回nullObject objg = phanRef.get();// 如果obj被置为null,当GC发现了虚引用,GC会将phanRef插入进我们之前创建时传入的refQueue队列// 注意,此时phanRef所引用的obj对象,并没有被GC回收,在我们显式地调用refQueue.poll返回phanRef之后// 当GC第二次发现虚引用,而此时JVM将phanRef插入到refQueue会插入失败,此时GC才会对obj进行回收Reference<? extends Object> phanRefP = refQueue.poll();

总结:在一个缓存系统里,如果所有的引用都采用强引用,那么你需要自己去手动把某些引用clean掉(引用至null),否则迟早会报OutOfMemoryError,缓存系统引入弱引用或者软引用的唯一原因是,把清除引用的事情交给java垃圾回收器来处理,缓存系统自己置身身外。




强可达(Strong Reachable)
1 0
原创粉丝点击