Java 内存泄露以及几种不同的引用

参考:
http://blog.csdn.net/renfufei/article/details/14138099#comments
http://xgtxxxx.iteye.com/blog/1622236
http://www.blogjava.net/zh-weir/archive/2011/02/23/345007.html
http://www.cnblogs.com/dolphin0520/p/3784171.html
http://www.cnblogs.com/blfshiye/p/4369949.html
http://www.iflym.com/index.php/java-programe/201407140001.html
http://blog.csdn.net/lyfi01/article/details/6415726#comments

Java有自己的垃圾回收机制,Java中几乎所有的内存兑现都是在堆上分配的(基本类型除外),然后由GC自动回收不再使用的内存。

1,什么是内存泄露

当某些对象不再被使用,但是由于仍然 被引用 而导致垃圾收集器不能回收他们。也就是说,应该回收的内存没有被回收。

简述Java内存泄露中的图片
这里写图片描述

一个内存泄露的场景:

当我们不断的向集合类内加入元素,而没有对应的删除机制,导致内存一直被占用,这样也不一定就会造成内存泄露。
当该集合类仅仅是一个局部变量的时候,当方法运行完成退出的时候,自然会被GC所回收,可是怕的是该集合类是一个全局的属性(比方类中的静态变量),那么会导致该集合类占用的内存仅仅增不减,这样就导致了内存的泄露。所以我们在使用全局性的集合类的时候要注意提供合适的删除策略或者定期清理策略。

2,复杂数据结构中的内存泄露问题

Java的GC机制是建立在跟踪内存的引用机制上的。
Java 创建的对象放在堆中,如果没有被引用时,就会被回收。所以对象回收满足:
- 没有引用指向它
- GC 运行
之前使用的引用都只是定义Object o。事实上,这只是Java**引用机制中一种默认**情况。

Java中还有其他的引用方式,通过使用这些特殊的引用机制与GC机制结合,就可以有效的防止内存泄露。

2.1 Java中的几种引用方式

这里写图片描述

1,强引用

Object obj = new Object();
Ref ref = new Ref(obj);

上述就是使用最普遍的强引用。只要ref 没有被GC,obj 这个对象就不会被GC
即使内存空间不足,Java虚拟机抛出OutOfMemoryError错误,也不会靠随意回收具有强引用的对象来解决内存不足问题。

如果想要中断强引用和某个对象之间的联系,可以显示的将引用值赋值为null。
这样JVM 就可以对其进行回收了。
比如Vector类的clear方法中就是通过将引用赋值为null来实现清理工作的:

  public synchronized void removeAllElements() {
        modCount++;
        // Let gc do its work
        for (int i = 0; i < elementCount; i++)
            elementData[i] = null;

        elementCount = 0;
    }

另外一个常见问题是缓存,如果使用强引用,缓存对象就会一直滞留在内存中不会被回收。

2,软引用(softReference)

在Java中用java.lang.ref.softReference类来表示。只有在内存不足的时候JVM 才会回收软引用对象。
这个特性很适合实现缓存,比如网页缓存,图片缓存等等。

import java.lang.ref.SoftReference;

public class Main {
    public static void main(String[] args) {

        SoftReference<String> sr = new SoftReference<String>(new String("hello"));
        System.out.println(sr.get());
    }
}

假如有一个应用需要读取大量的本地图片,如果每次读取图片都从硬盘读取,则会严重影响性能,但是如果全部加载到内存当中,又有可能造成内存溢出,此时使用软引用可以解决这个问题。

  设计思路是:用一个HashMap来保存图片的路径 和 相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题。
 
软引用可以和引用队列 ReferenceQueue 联合使用,如果软引用所引用的对象被垃圾回收器回收,JVM 就会把这个软引用加入到与之关联的引用队列中。

WeakReference<byte[]> weakReference = new WeakReference<byte[]>(bytes, referenceQueue);

3,弱引用(WeakReference)

垃圾回收时,无论内存是否充足,都会回收弱引用关联的对象。
垃圾回收期并不会总在第一次就找到弱引用,而是会找几次才能找到。

弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

4,幽灵引用(PhantomReference)

ReferenceQueue queue = new ReferenceQueue ();  
PhantomReference pr = new PhantomReference (object, queue); 

该引用形同虚设,不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,get方法返回null
虚引用主要用来跟踪对象被垃圾回收的活动。它必须要和ReferenceQueue 联合使用。
GC 发现了虚引用对象,会把对象插入ReferenceQueue队列与软引用和弱引用不同, 先把PhantomRefrence对象添加到它的ReferenceQueue中.然后在释放虚可及的对象.
如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

5,引用队列 ReferenceQueue

看到 :ReferenceQueue 的使用 中的转过来:

Object obj = new Object();
Ref ref = new Ref(obj);

上面强引用的例子,如果希望obj 没有其他的引用,只有ref 的引用时,就吧它GC掉,就可以使用上面的几种Reference对象来实现。
如果希望obj 被回来的时候通知用户线程,进行额外的处理,就需要使用ReferenceQueue了。
当一个obj被gc掉之后,其相应的包装类,即ref对象会被放入queue中。我们可以从queue中获取到相应的对象信息,同时进行额外的处理。

6,如何判断一个对象的可及性

参考这里:
很多时候一个对象会被多个对象所引用。
这里写图片描述

  • 单条引用路径可及性判断:在这条路径中,最弱的一个引用决定对象的可及性。
  • 多条引用路径可及性判断:几条路径中,最强的一条的引用决定对象的可及性。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值