java中软引用与弱引用的笔记

前言

最近经常在做关于引用性能优化方面的工作。总结了一下发现解决java内存泄露的主要问题是一些变量或者context被引用后,没用及时回收导致了内存没得到及时释放。但我们可以用软引用和弱引用来解决这类问题。

简单介绍

平常我们定义一个对象,并对对象使用。其实默认是对其使用了强引用

Object o = new Object();

平时这样使用其实问题不大,但举个例子:
当在Activity中创建Fragment,把Fragment对象传入到另一个view中,view中执行一系列的耗时操作,但然而,用户并没用等这些操作完成,就已经关闭了这个fragment。问题来了,fragment能真正关闭吗?答案是否定的,由于view占用了这个fragment的强引用,这个fragment是不能被gc的。
此处伪代码:

 private HeadClubActivityDetailView clubActivityDetailView;
public void  onCreate(){
     clubActivityDetailView = new HeadClubActivityDetailView(getActivity());
     clubActivity = result.getActivity();
     clubActivity.setnCurrentTime((int) result.getnTime());
     WeakReference weakReference = new WeakReference(clubActivity);
     clubActivityDetailView.setData(weakReference);
}
public void setData(WeakReference<ClubActivity> weakReference) {
        this.clubActivity = weakReference.get();
        if (clubActivity == null)
            return;

        String theme = clubActivity.getStrName();
        String initator = clubActivity.getStrOrganiserName(); //发起方
        String school = clubActivity.getStrAgencyname();
       ```````````````````````````
        }

以上代码可以比较有效的解决对象被其他单例或者另一个view等情况强制引用导致无法回收的问题。其实就是把你要传递的对象通过弱引用进行处理后传入到要使用对象的地方,通过get获取,这样就可以在需要gc的时候回收对象了

简单叙述了一下使用弱引用的案例,现在我们就记录一下他们的定义吧
弱引用: 如果你希望能随时取得某对象的信息,但又不想影响此对象的垃圾收集,那么你应该用 Weak Reference来记住此对象,而不是用一般的 reference。
软引用: Soft Reference 虽然和 Weak Reference 很类似,但是用途却不同。 被 Soft Reference指到的对象,即使没有任何 Direct Reference,也不会被清除。一直要到 JVM 内存不足时且 没有 DirectReference 时才会清除,SoftReference 是用来设计 object-cache 之用的。如此一来SoftReference 不但可以把对象 cache 起来,也不会造成内存不足的错误 (OutOfMemoryError)

这里写图片描述

简单记录一下存在内存泄露可能的情况

1.单例模式
使用单例模式的时候也有可能导致内存泄漏。因为单例对象初始化后将在JVM的整个生命周期内存在,如果它持有一个外部对象(生命周期比较短)的引用,那么这个外部对象就不能被回收,而导致内存泄漏。如果这个外部对象还持有其它对象的引用,那么内存泄漏会更严重,因此需要特别注意此类情况。这种情况就需要考虑下单例模式的设计会不会有问题,应该怎样保证不会产生内存泄漏问题。
2.外部模块引用
调用外部模块的时候,也应该注意防止内存泄漏。如模块A调用了外部模块B的一个方法,如:
public void register(Object o)
这个方法有可能就使得A模块持有传入对象的引用,这时候需要查看B模块是否提供了去除引用的方法,如unregister()。这种情况容易忽略,而且发生了内存泄漏的话,比较难察觉,应该在编写代码过程中就应该注意此类问题。
3.监听器
在Java中,我们经常会使用到监听器,如对某个控件添加单击监听器addOnClickListener(),但往往释放对象的时候会忘记删除监听器,这就有可能造成内存泄漏。好的方法就是,在释放对象的时候,应该记住释放所有监听器,这就能避免了因为监听器而导致的内存泄漏。

4.Handle的使用
Hnadle的随意使用也很容易造成内存泄露,有效的解决方法是使用静态内部类去定义一个handler

private static class MyHandler extends Handler {
    private final WeakReference<SampleActivity> mActivity;

    public MyHandler(SampleActivity activity) {
      mActivity = new WeakReference<SampleActivity>(activity);
    }

    @Override
    public void handleMessage(Message msg) {
      SampleActivity activity = mActivity.get();
      if (activity != null) {
        // ...
      }
    }
  }

复制一些网上找的优化内存泄露的小建议:

Listview的item泄露
这个是入门问题了,加入ViewHolder可以减少findViewById的时间,或者使用RecyclerView,来解决“滑动很卡”的问题。这个实质也是一个单例。

StringBuilder
尽量使用StringBuilder,而不用String来累加字符串,你现在还记得String,StringBuilder,StringBuffer的区别吗?

StringBuffer其实是给StringBuilder加了同步锁;其实你使用Log.d(TAG,”xx” + “yy”)这类写法后,编译器生成的代码已经自动帮你变成StringBuilder了

如何正确的操作字符串?请参考编程随想的《Java性能优化[2]:字符串过滤实战》
多用基本类型
使用int而不用Integer,较少的对象花销。在Android中使用sparseArrayMap取代HashMap就是把key变成了int,而一定程度上减小了内存占用。

当然这个也是相对的,比如RxJava为了提高代码可读性使用了大量的包装,性能损失相比项目整体管理是可以接受的
Native代码不受GC控制
Native层面的代码不受到GC控制,又是长篇大论了,取决于C的水平。Malloc的内存一定要free,free后记得把指针置空,还有new 与delete的区别,一笔带过吧。当然,我们可以用Go语言进行NDK开发,那么又是另一套GC方案了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值