网站首页 > 技术文章 正文
整体架构
强引用
强引用是默认支持,当内存不足的时候,JVM开始垃圾回收,对于强引用的对象,就算是出现了OOM也不会回收对象。
强引用是最常见的普通对象引用,只要还有强引用指向对象,对象就存活,垃圾回收器不会处理存活对象。一般把一个对象赋给一个引用变量,这个引用变量就是强引用。当一个对象被强引用变量所引用,它就处于可达状态,是不会被垃圾回收的,即使之后都不会再用到了,也不会回收。因此强引用是造成Java内存泄漏的主要原因之一。
对于一个普通对象,如果没有其他引用关系,只要超过了引用的作用域或者显式地将相应的强引用赋值为null,一般认为就是可以被垃圾回收了。(具体的回收时机看垃圾回收策略)
下例中,b就是强引用。
1 public static void main(String[] args) {
2 Object a = new Object();
3 Object b = a;
4 a = null;
5 System.out.println(b);//java.lang.Object@4554617c
6 }
软引用
软引用是一种相对强引用弱化了一些的引用,用java.lang.ref.SoftReference实现,可以让对象豁免一些垃圾收集。当系统内存充足的时候,不会被回收;当系统内存不足的时候,会被回收。
软引用一般用于对内存敏感的程序中,比如高速缓存。
1 import java.lang.ref.SoftReference;
2
3 public class SoftReferenceDemo {
4 public static void main(String[] args) {
5 Object a = new Object();
6 SoftReference<Object> softReference = new SoftReference<>(a);//软引用
7 //a和软引用指向同一个对象
8 System.out.println(a);//java.lang.Object@4554617c
9 System.out.println(softReference.get());//java.lang.Object@4554617c 10
11 //内存够用,软引用不会被回收
12 a = null; 13 System.gc();//内存够用不会自动gc,手动唤醒gc
14 System.out.println(a);//null
15 System.out.println(softReference.get());//java.lang.Object@4554617c 16
17 //内存不够用时
18 try{ 19 //配置Xms和Xmx为5MB
20 byte[] bytes = new byte[1024*1024*30];//设置30MB超内存
21 }catch (Throwable e){ 22 e.printStackTrace(); 23 }finally { 24 System.out.println(a);//null
25 System.out.println(softReference.get());//null
26 }
27 }
28 }
使用场景
一个应用需要读取大量的本地图片,如果每次读取都从硬盘读取会严重影响性能,如果一次性全部加载到内存,内存可能会溢出。
可以使用软引用解决这个问题,使用一个HashMap来保存图片路径和图片对象管理的软引用之间的映射关系,内存不足时,JVM会自动回收缓存图片对象的占用空间,有效地避免了OOM(Out Of Memory)问题。
Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>
弱引用
弱引用需要用java.lang.ref.WeakReference实现,它比软引用的生存期更短,对于弱引用的对象来说,只要垃圾回收机制一运行,不管JVM的内存空间是否够,都会回收该对象的占用内存。
1 import java.lang.ref.WeakReference;
2
3 public class SoftReferenceDemo {
4 public static void main(String[] args) {
5 Object a = new Object();
6 WeakReference<Object> softReference = new WeakReference<>(a);//软引用
7 //a和弱引用指向同一个对象
8 System.out.println(a);//java.lang.Object@4554617c
9 System.out.println(softReference.get());//java.lang.Object@4554617c 10
11 //内存够用,弱引用也会被回收
12 a = null; 13 System.gc();//内存够用不会自动gc,手动唤醒gc
14 System.out.println(a);//null
15 System.out.println(softReference.get());//null
16 }
17 }
关于WeakHashMap
1 public static void weakHashMapTest() {
2 Integer key = new Integer(1);
3 String value = "李四";
4 Map<Integer,String> weakHashMap = new WeakHashMap();
5 weakHashMap.put(key, value);
6 System.out.println(weakHashMap);//{1=李四}
7 key = null;
8 System.gc();
9 System.out.println(weakHashMap);//{}10 }
11
12 public static void hashMapTest() {
13 HashMap<Integer,String> map = new HashMap<>();
14 Integer key = 1;
15 String value = "张三";
16 map.put(key,value);
17 System.out.println(map);//{1=张三}
18 key = null;
19 System.gc();
20 System.out.println(map);//{1=张三}
21 }
在HashMap中,键被置为null,唤醒gc后,不会垃圾回收键为null的键值对。但是在WeakHashMap中,键被置为null,唤醒gc后,键为null的键值对会被回收。
虚引用
虚引用要通过java.lang.ref.PhantomReference类来实现,虚引用不会决定对象的生命周期,如果一个对象只有虚引用,就相当于没有引用,在任何时候都可能会被垃圾回收器回收。它不能单独使用也不能访问对象,虚引用必须和引用队列联合使用。
虚引用的主要作用是跟踪对象被垃圾回收的状态,仅仅是提供一种确保对象被finalize以后,做某些事情的机制。
PhantomReference的get方法总是返回null,因此无法访问对应的引用对象,设置虚引用关联唯一的目的是在对象被收集器回收的时候收到一个系统通知,或者后续添加进一步的处理。Java允许使用finalize()方法在垃圾回收器将对象从内存中清理出去之前做一些必要的清理工作。【例如实现一个监控对象的通知机制】
引用队列
WeakReference和ReferenceQueue的联合使用效果:
1 public static void weakReferenceTest() {
2 Object a = new Object();
3 ReferenceQueue<Object> queue = new ReferenceQueue<>();
4 WeakReference<Object> weakReference = new WeakReference<>(a,queue);
5 System.out.println(a);//java.lang.Object@4554617c
6 System.out.println(weakReference.get());//java.lang.Object@4554617c
7 System.out.println(queue.poll());//null
8 System.out.println("-------------------");
9 a = null;
10 System.gc();
11 System.out.println(a);//null
12 System.out.println(weakReference.get());//null 13 //虚引用在回收之前被加入到了引用队列中
14 System.out.println(queue.poll());//java.lang.ref.WeakReference@74a14482
15 }
PhantomReference和ReferenceQueue的联合使用效果:
1 public static void phantomReferenceTest() {
2 Object a = new Object();
3 ReferenceQueue<Object> queue = new ReferenceQueue<>();
4 PhantomReference<Object> phantomReference = new PhantomReference<>(a,queue);
5 System.out.println(a);//java.lang.Object@4554617c
6 System.out.println(phantomReference.get());//null
7 System.out.println(queue.poll());//null
8 System.out.println("-------------------");
9 a = null;
10 System.gc();
11 System.out.println(a);//null
12 System.out.println(phantomReference.get());//null
13 //引用在回收之前被加入到了引用队列中
14 System.out.println(queue.poll());//java.lang.ref.WeakReference@74a14482
15 }
总结
强引用:不回收。
软引用:内存不够就回收。
弱引用:一定回收。
虚引用:一定回收,get出来就是null,引用形同虚设,主要和引用队列联合使用,在finalize之前会被放到引用队列中。
与根对象没有引用关系的:引用不可达,一定回收。
猜你喜欢
- 2024-10-28 美团面试:熟悉哪些JVM调优参数,幸好我准备过
- 2024-10-28 Java虚拟机:Jvm概念和原理详解以及GC机制的分析
- 2024-10-28 JVM 的内存模型(jvm1.8内存模型)
- 2024-10-28 JDK、JRE、JVM,是什么关系?(jdk jrejvm的区别)
- 2024-10-28 一个 JVM 参数引发的频繁 CMS GC(当产生一个异常时,jvm会做什么)
- 2024-10-28 JVM系列一:JVM内存组成及分配(jvm的内存分配)
- 2024-10-28 谈谈JMM与JVM的相关知识(jmm jvm juc)
- 2024-10-28 常见的JVM参数配置(常见的JVM参数配置有哪些)
- 2024-10-28 一份详细介绍JVM的资料(对比JDK8和JDK7)
- 2024-10-28 理解JVM运行时数据区域,看这一篇文章就够了
- 11-26Win7\8\10下一条cmd命令可查得笔记本电脑连接过的Wifi密码
- 11-26一文搞懂MySQL行锁、表锁、间隙锁详解
- 11-26电脑的wifi密码忘记了?一招教你如何找回密码,简单明了,快收藏
- 11-26代码解决忘记密码问题 教你用CMD命令查看所有连接过的WIFI密码
- 11-26CMD命令提示符能干嘛?这些功能你都知道吗?
- 11-26性能测试之慢sql分析
- 11-26论渗透信息收集的重要性
- 11-26如何查看电脑连接过的所有WiFi密码
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)