Java|Java 四种引用

1.什么是引用(对象,引用)
2.哪四种及其引用场景
3.应用场景
1.Person person = new Person();
疑问:person是对象吗?不是对象的话,谁是对象,谁是引用?
分析:如果person是一个对象的话,为什么不直接这么写Person person; 为什么还要通过new来创建对象呢?
解答:所以person是一个引用,是指向一个可以指向Person类的对象的引用。真正创建对象的语句是右边的new Person("张三");
Java|Java 四种引用
文章图片
这里对对象,引用做下解释,至于jvm会在以后分享 2.四种:强引用,软引用,弱引用,虚引用
强引用:
介绍:一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误 终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题
软引用(SoftReference):
介绍:内存充足: GC,不会回收当前的软引用
内存临近阈值或不足:GC,发现某一对象的引用只具有软引用当前软引用就会被回收。
问题:那么当一对象除了具有软引用还具有硬引用,GC时,会被回收吗?
肯定不会,只会回收只具有软引用的对象
使用场景:
1>处理图片这种占用内存大的情况
Java|Java 四种引用
文章图片
通过软引用的get()方法,取得drawable对象实例的强引用,发现对象被未回收。在GC在内存充足的情况下,不会回收软引用对象。此时view的背景显示
实际情况中,我们会获取很多图片.然后可能给很多个view展示, 这种情况下很容易内存吃紧导致oom,内存吃紧,系统开始会GC。这次GC后,drawables.get()不再返回Drawable对象,而是返回null,这时屏幕上背景图不显示,说明在系统内存紧张的情况下,软引用被回收。
使用软引用以后,在OutOfMemory异常发生之前,这些缓存的图片资源的内存空间可以被释放掉的,从而避免内存达到上限,避免Crash发生。
2>从软引用的特点可能会想,可以用软引用做缓存啊,那为什么不用它来做呢?
1.关于这部分缓存被回收时,并没有一套机制去进行衡量,例如先回收离上次使用间隔时长最长的,而是随GC随机回收;
2.当手机内存使用比较高的时候,那么在理论上来说,GC的频率也就会更高,需要不断的释放掉相应的内存来腾出空间,而在这个时候,也将意味着软引用,也将会被高频率清理,在这个过程中起到缓存的实质性质效果很低,软应用刚创建好不一会就被清理,不一会就被清理,站在性能优化的角度来说,效果并不明显,并且在被回收后还是需要不断重新创建,这也是消耗性能的
所以关于图片的缓存,谷歌后来推出了LruCache,底层是LinkHashMap解决了上述的第一点问题,而可以设定存储大小则是很好的解决了第二点问题(LruCache不做详解,自行百度)
注意:获取对象后要进行判空
3>浏览器的后退按钮。按后退时,后退时显示的网页内容是重新进行请求还是从缓存中取出呢?当然看具体的业务需求了(只分析缓存这种)
如果一个网页只是单存的页面展示,没有与后端进行交互的数据,在浏览结束的时候,我们进行了内容回收,进入下个页面,按back键返回,这个网页就需要重新构建,可是如果将网页存储到内存中会造成内存的大量浪费,甚至会造成内存溢出
这时候就可以使用软引用
弱引用(WeakReference):
介绍:随时可能会被垃圾回收器回收,不一定要等到虚拟机内存不足时才强制回收。要获取对象时,同样可以调用get方法。
如果一个对象只具有弱引用,那么在垃圾回收器线程扫描的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
问题1:
Java|Java 四种引用
文章图片
1>会打印什么呢???
打印了n次"Object is alive"后打印了Object has been collected
data.get()为什么得到的是null呢?myDate是强引用,网上大部分的解释是:
这是因为java的编译器在发现进入while循环之后, 发现myDate 已经没有被使用了, 所以进行了优化,将其置空
2>那怎样让他不为null呢?
Java|Java 四种引用
文章图片
当然里面有调用myDate的地方就可以了
问题2:
Handler造成内存泄露的原因就不说了,解决内存泄露的方法有两种:
1>从逻辑上解决:在页面销毁的时候,removeCallbacksAndMessages
2>但是鉴于调用者有时候会因为各种原因,没写,造成问题,所以可以从代码设计上解决
Java|Java 四种引用
文章图片
这应该是见到最常见解决handler内存泄露的代码了
1>static 修饰的类:
匿名内部类会持有外部类的强引用,改为静态内部类
为什么非静态内部类为什么持有外部类的this引用呢???
这里不做赘述,详情请看:非静态内部类为什么持有外部类的this引用 - daimengs的博客 - CSDN博客
2>不能持有外部引用,就不能调用外部类方法,可以改为持有外部的弱引用
鉴于它何时被回收是不可确定的(由GC运行的不确定性所决定的),所以每次调用的时候记得判空
虚引用:
介绍:虚引用是所有引用类型中最弱的一个。一个持有虚引用的对象,和没有引用几乎是一样的,随时都可能被垃圾回收器回收。当试图通过虚引用的get()方法取得强引用时,总是会失败。并且,虚引用必须和引用队列一起使用,它的作用在于跟踪垃圾回收过程。 当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在垃圾回收后,销毁这个对象,将这个虚引用加入引用队列
比较:
Java|Java 四种引用
文章图片
摘自网络 弱引用与软引用:
1>这是单存想解决oom问题的时候,建议用软引用,对于性能比较在意,想回收占内存比较大的对象,用弱引用
【Java|Java 四种引用】2>可以根据对象是否经常使用来判断。如果该对象可能会经常使用的,就尽量用软引用。如果该对象不被使用的可能性更大些,就可以用弱引用
参考链接:
[转]Java 的强引用、弱引用、软引用、虚引用 - gudi - 博客园
浅谈Java中的对象和引用 - 海 子 - 博客园
android开发四种引用的详解 - 李苏哲的博客 - CSDN博客

    推荐阅读