每天一个面试题:四种引用
- 四种引用基本介绍
- 实例Demo
- - 虚引用
- 弱引用防止内存泄漏
- 弱引用
- Debug分析源码
开始全新的学习,沉淀才会有产出,一步一脚印!
面试题系列搞起来,这个专栏并非单纯的八股文,我会在技术底层的基础上,不至于Debug,还会做一些实例的实现,实现一些简单的Demo,或者用于我做过的项目中去;
代码会同步在我的gitee中去,觉得不错的同学记得一键三连求关注,感谢:
链接: Reference
四种引用基本介绍
- 强引用就是正常的new实例,这种关系是单独一对一的,由GCroot的引用链确定,不会被GC自动回收,需要手动收回;
-
软引用,是基于SoftReference确定的,类似于代理加工实现,首次gc不回收,内存不足回收
软参考对象,由垃圾自行决定清除收集器响应内存需求。 软引用最常被用来实现内存敏感型缓存 public class SoftReference<T> extends Reference<T> {
-
弱引用:只要gc就删除
-
虚引用:配合了一个队列进行使用,gc去将虚引用的对象及其外部资源回收掉
实例Demo
- 虚引用
public class TestPhantomfegerence {
static class MyResource extends PhantomReference<String>{
//继承了虚引用类,构造方法中对应了 构造的 对象和队列
public MyResource(String referent, ReferenceQueue<? super String> q) {
super(referent, q);
}
public void clean(){
System.out.println("clean");
}
}
进行测试
public static void main(String[] args) {
ReferenceQueue<String> queue = new ReferenceQueue<>();
List<MyResource> list = new ArrayList<>();
list.add(new MyResource(new String("a"), queue));
list.add(new MyResource("b", queue));
list.add(new MyResource(new String("c"), queue));
//调用系统GC
System.gc();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
Object obj;
// gc后,如果存在资源,就打印,可以看到new的对象被打印了
while((obj = queue.poll())!=null){
if(obj instanceof MyResource ){
((MyResource) obj).clean();
}
}
}
}
弱引用防止内存泄漏
ThreadLocalMap中存在内存泄漏问题,这里可以通过一下这种方式实现
public class TestWeakReference {
public static void main(String[] args) {
MyweakMap map = new MyweakMap(5);
map.put(0, new String("a"), "1");
map.put(1, ("b"), "2");
map.put(2, ("c"), "3");
map.put(3, new String("d"), "3");
System.out.println(map);
System.gc();
System.out.println(map.get("a"));
System.out.println(map.get("b"));
System.out.println(map.get("c"));
System.out.println(map.get("d"));
map.clean();
System.out.println(map);
}
static class MyweakMap{
static ReferenceQueue<Object> queue = new ReferenceQueue<>();
static class Entry extends WeakReference<String> {
String value;
//这里的value设定,让key成为了一个弱引用,value成强引用
public Entry(String key, String value) {
super(key,queue);
this.value = value;
}
@Override
public String toString() {
return "Entry{" +
"value='" + value + '\'' +
'}';
}
}
这里是通过判断当前的key是否为null来进行的
public void clean(){
Object object;
while((object=queue.poll())!=null){
for (int i = 0; i < table.length; i++) {
if(table[i]==object){
table[i]=null;
}
}
}
}
如果为null,就将当前table,也就是对象Entry[]对应的单个Entry直接设置为null, static class Entry extends WeakReference<String> {
这就断开了联系
public MyweakMap(int init){
table= new Entry[init];
}
Entry[] table;
public void put(int index, String key, String value){
table[index] = new Entry(key, value);
}
public String get(String key){
for(Entry entry : table){
if(entry!=null){
String k = entry.get();
if(k!=null&&k.equals(key)){
return entry.value;
}
}
}
return null;
}
@Override
public String toString() {
return "MyweakMap{" +
"table=" + Arrays.toString(table) +
'}';
}
}
}
弱引用
public class TestSoft {
static class WeakReferenceDemo extends WeakReference<String> {
public WeakReferenceDemo(String referent) {
super(referent);
System.out.println(referent);
}
}
public static void main(String[] args) {
List<WeakReference> list = new ArrayList<>();
list.add(new TestSoft.WeakReferenceDemo(new String("a")));
list.add(new TestSoft.WeakReferenceDemo(("b")));
list.add(new TestSoft.WeakReferenceDemo(new String("c")));
System.out.println(list.get(0).get());
System.gc();
System.out.println(list.get(0).get());
}
}
结果展示 a b c a null
Debug分析源码
引用的底层很简单
public class WeakReference<T> extends Reference<T> {
public WeakReference(T referent) {
super(referent);
}
public WeakReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
一个泛型类
public abstract class Reference<T> {
private T referent; /* Treated specially by GC */
volatile ReferenceQueue<? super T> queue;
链表结构
@SuppressWarnings("rawtypes")
Reference next;
transient private Reference<T> discovered; /* used by VM */
static private class Lock { };
private static Lock lock = new Lock();
private static Reference<Object> pending = null;
实现了一个静态内部类ReferenceHandler
private static Lock lock = new Lock();
加载一个类锁
private static class ReferenceHandler extends Thread {
ReferenceHandler(ThreadGroup g, String name) {
super(g, name);
}
public void run() {
for (;;) {
Reference<Object> r;
synchronized (lock) {
if (pending != null) {
r = pending;
pending = r.discovered;
r.discovered = null;
} else {
try {
try {
lock.wait();
} catch (OutOfMemoryError x) { }
} catch (InterruptedException x) { }
continue;
}
}
// Fast path for cleaners
if (r instanceof Cleaner) {
((Cleaner)r).clean();
continue;
}
ReferenceQueue<Object> q = r.queue;
if (q != ReferenceQueue.NULL) q.enqueue(r);
}
}
}
static {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
for (ThreadGroup tgn = tg;
tgn != null;
tg = tgn, tgn = tg.getParent());
Thread handler = new ReferenceHandler(tg, "Reference Handler");
/* If there were a special system-only priority greater than
* MAX_PRIORITY, it would be used here
*/
handler.setPriority(Thread.MAX_PRIORITY);
handler.setDaemon(true);
handler.start();
}
public T get() {
return this.referent;
}
public void clear() {
this.referent = null;
}
public boolean enqueue() {
return this.queue.enqueue(this);
}
/* -- Constructors -- */
Reference(T referent) {
this(referent, null);
}
Reference(T referent, ReferenceQueue<? super T> queue) {
this.referent = referent;
this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
}
}