我们知道Java语言中没有指针,取而代之的是引用reference。Java中的引用又可以分为四种:强引用,弱引用(WeakReference),软引用(SoftReference),虚引用(PhantomReference)。其中强引用,就是我们平时使用的最多的最普通的引用,虚引用一般我们是没有机会使用到的。所以我们主要了解下 WeakReference 和 SoftReference(除了上面说的四种引用之外,其实还有一种引用——原子引用AtomicReference,用于并发编程环境)。

1. 先上一段代码:

public class ReferenceTest {
public static void main(String[] args){
LinkedList<byte[]> list = new LinkedList<>();
for(int i=0; i<1024; i++){
list.add(new byte[1024*1024]);
}
}
}

上面的代码会抛出:Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

堆内存溢出。因为我们不断的在堆上分配一个 1M 大小的 byte[]对象,并且将该引用加入到 list 中,循环1024次,需要占用 1G 的堆内存,从而导致 heap space OutOfMemory.

2. 我们使用 WeekReference 对代码进行修改:

public class ReferenceTest {
public static void main(String[] args) {
long beginTime = System.nanoTime();
LinkedList<WeakReference<byte[]>> list = new LinkedList<>();
for (int i = 0; i < 1024; i++) {
list.add(new WeakReference<>(new byte[1024 * 1024]));
}
long endTime = System.nanoTime();
System.out.println(endTime - beginTime);
}
}

输出的结果:195947704 (0.19秒)

我们发现堆内存溢出的错误没有了。这是什么原因呢。因为我们使用了 弱引用WeekReference 来引用堆上的 1M 的byte[]对象,而弱引用WeekReference引用的对象,如果仅仅只被弱引用,而没有被强引用的话,在下一次GC时,就会回收该对象占用的内存,所以不会内存溢出。

3. 我们使用 SoftReference 对代码进行修改:

public class ReferenceTest {
public static void main(String[] args) {
long beginTime = System.nanoTime();
LinkedList<SoftReference<byte[]>> list = new LinkedList<>();
for (int i = 0; i < 1024; i++) {
list.add(new SoftReference<>(new byte[1024 * 1024]));
}
long endTime = System.nanoTime();
System.out.println(endTime - beginTime);
}
}

输出结果:1499904286 (1.5秒)

我们发现堆内存溢出的错误也没有了。因为我们使用了 软引用SoftReference 来引用堆上的 1M 的byte[]对象,而软引用SoftReference引用的对象,如果仅仅只被软引用,而没有被强引用的话,在内存空间不足时,GC 就会回收该对象占用的内存,所以不会内存溢出。

但是我们注意到 采用WeekReference和采用SoftReference所花费的时间,有接近10被的差距。原因应该是,SoftReference只有在内存空间不足时,GC才会回收对象占用的空间,而这时进行的是 full GC,full GC会导致 STW 程序暂停,所以花费的时间过多。

4. 总结

强引用:只要堆上的对象,被至少一个强引用所指向,那么GC就不会回收该对象的内存空间。

弱引用:只要堆上的对象仅仅只被弱引用所指向,不管当前内存空间是否足够,下次GC都会回收对象的内存空间。

软引用:只要堆上的对象仅仅只被软引用所指向,并且当内存空间不足时,GC才会回收对象的内存空间。

WeakReference 和 SoftReference一般使用在构造一个缓存系统,比如使用一个map来构造。因为缓存系统是一个“全生命期”的对象,系统停止,缓存对象才会被销毁,所以当我们不断的想缓存对象中添加对象时,那么就会导致该缓存对象map所引用的对象越来越多,而因为是强引用,这些被放进map缓存了的对象不能被GC所回收,那么就导致系统堆内存占用会越来越大,从而最终导致内存溢出。

那么此时我们就可以使用 WeakReference 或 SoftReference了,将强引用通过WeakReference 和 SoftReference 包装之后,变成弱引用和软引用,那么当缓存中的对象,仅仅被缓存map所引用时,那么分别在下次GC和内存不足GC时就会回收这些对象占用的内存。其实JDK给我们提供了一个专门的类:WeakHashMap ,弱引用的hashMap,所以构造缓存系统是,我们可以考虑使用它。

其实这里引出了另外一个问题,jdk中众多的map,我们应该如何进行选择

HashMap

ConcurrentHashMap

TreeMap

WeakHashMap

LinkedHashMap

Collections.synchronizedMap

Hashtable

等等。我们在选择一个map时,应该好好的考虑下,那个更加适合我们的需求。

Java中的 WeakReference 和 SoftReference的更多相关文章

  1. Java中关于WeakReference和WeakHashMap的理解

    新美大的10月11日的笔试中有一道选择题,让选择函数返回结果,代码如下: private static String test(){ String a = new String("a&quo ...

  2. 谈谈java中的WeakReference

    Java语言中为对象的引用分为了四个级别,分别为 强引用 .软引用.弱引用.虚引用. 本文只针对java中的弱引用进行一些分析,如有出入还请多指正. 在分析弱引用之前,先阐述一个概念:什么是对象可到达 ...

  3. 【转】Java中关于WeakReference和WeakHashMap的理解

    新美大的10月11日的笔试中有一道选择题,让选择函数返回结果,代码如下: private static String test(){ String a = new String("a&quo ...

  4. Java中WeakHashMap实现原理深究

    一.前言 我发现Java很多开源框架都使用了WeakHashMap,刚开始没怎么去注意,只知道它里面存储的值会随时间的推移慢慢减少(在 WeakHashMap 中,当某个“弱键”不再正常使用时,会被从 ...

  5. Java 中 WeakReference 与 SoftReference 的区别?

    虽然 WeakReference 与 SoftReference 都有利于提高 GC 和 内存的效率, 但是 WeakReference ,一旦失去最后一个强引用,就会被 GC 回收,而软引用 虽然不 ...

  6. Java引用总结--StrongReference、SoftReference、WeakReference、PhantomReference

    Java引用总结--StrongReference.SoftReference.WeakReference.PhantomReference 1 Java引用介绍 Java从1.2版本开始引入了4种引 ...

  7. 【转】Java之WeakReference与SoftReference使用讲解

    Java 2 平台引入了 java.lang.ref 包,其中包括的类可以让您引用对象,而不将它们留在内存中.这些类还提供了与垃圾收集器(garbage collector)之间有限的交互. 1.先“ ...

  8. java基础回顾(六)——WeakReference、SoftReference

    在Java里, 当一个对象o被创建时, 它被放在Heap里. 当GC运行的时候, 如果发现没有任何引用指向o, o就会被回收以腾出内存空间. 或者换句话说, 一个对象被回收, 必须满足两个条件: 1) ...

  9. Java的引用StrongReference、 SoftReference、 WeakReference 、PhantomReference

    1. Strong Reference StrongReference 是 Java 的默认引用实现,  它会尽可能长时间的存活于 JVM 内, 当没有任何对象指向它时 GC 执行后将会被回收 @Te ...

随机推荐

  1. CentOS6.5菜鸟之旅:纯转载Linux目录结构

    来自:http://www.iteye.com/topic/1125162 使用linux也有一年多时间了  最近也是一直在维护网站系统主机  下面是linux目录结构说明 本人使用的是centos系 ...

  2. JS魔法堂:精确判断IE的文档模式by特征嗅探

    一.前言 苦逼的前端攻城狮都深受浏览器兼容之苦,再完成每一项功能前都要左顾右盼,生怕浏览器不支持某个API,生怕原生API内含臭虫因此判断浏览器类型和版本号成了不可绕过的一道关卡,而特征嗅探是继浏览器 ...

  3. http与websocket(基于SignalR)两种协议下的跨域基于ASP.NET MVC--竹子整理

    这段时间,项目涉及到移动端,这就不可避免的涉及到了跨域的问题.这是本人第一次接触跨域,有些地方的配置是有点麻烦,导致一开始的不顺. 至于websocket具体是什么意义,用途如何:请百度. 简单说就是 ...

  4. javaScript一些函数--Math()

    1.不能显式地创建一个Math对象,直接使用它就可以了: 2.Math对象不能存储数据,和String,Date对象不同: 3.前面知道了parseInt()函数会通过消去小数点后面的一切,来使一个小 ...

  5. dp --- CSU 1547: Rectangle

    Rectangle Problem's Link:   http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1547 Mean: 给你一些宽为1或2 的木 ...

  6. 重构第8天:使用委托代替继承(Replace Inheritance with Delegation)

    理解:根本没有父子关系的类中使用继承是不合理的,可以用委派的方式来代替. 详解:我们经常在错误的场景使用继承.继承应该在仅仅有逻辑关系的环境中使用,而很多情况下却被使用在达到方便为目的的环境中. 看下 ...

  7. for循环的嵌套,for循环的穷举迭代

    for循环的嵌套            输入一个正整数,求阶乘的和 嵌套            Console.Write("请输入一个正整数:");            int ...

  8. sql分页存储过程

    ALTER PROCEDURE [dbo].[P_SplitPagesQuery] @TablesName NVARCHAR(MAX),--表名或视图名(只能传单一表名) @PK NVARCHAR(M ...

  9. LINQ TO XML 个人的一些心得1

    最近没事做,刚来到一个新公司.写了一些处理xml的项目  就是把一些xml的数据处理后存储到数据库中.原本还是准备用原来的xml来写的.在群里有个人说,用linq to xml 好了,比较快捷.就看了 ...

  10. 自定义饼图(PieChart)各个PieSlice的外观

    C1Chart提供了Theme和Palette接口,其中内置了很多配色方案,调整外观. <c1chart:C1Chart Margin="0,0,8,8" MinHeight ...