Android内存优化——虚引用,弱引用,软引用的使用及内存分析工具

一、虚引用

虚引用在实际的开发过程中应用的比较少。虚引用有一下几个特点:
(1)虚引用在垃圾回收器回收的时候被回收
(2)虚引用在通过get()方法获取的对象都为空,所以也被称为幽灵引用

(3)虚引用不会决定一个对象的生命周期,如果一个对象持有一个虚引用,那么它就和没有任何引用是一样的。

所以,根据上述的三个特点可以知道,虚引用主要用来监听所关联的对象什么时候被回收。操作如下:

public class PhantomTest {
    ReferenceQueue<Object>referenceQueue = new ReferenceQueue<>();
    Object obj = new Object();
    PhantomReference phantomReference = new PhantomReference(obj,referenceQueue);

    public void start(){
        new Thread(()->{
            System.out.println("reference.get()="+phantomReference.get());
            PhantomReference<Object>reference = null;
            try {
                reference = (PhantomReference<Object>) referenceQueue.remove();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            System.out.println("虚引用回收:"+reference);
        }).start();
    }


    public static void main(String[] args) throws InterruptedException {
        PhantomTest test = new PhantomTest();
        test.start();
        test.obj = null;
        Thread.sleep(5000);
        System.gc();
        Thread.sleep(5000);

    }
}

输出如下:

reference.get()=null
虚引用回收:java.lang.ref.PhantomReference@2951cacb

(1)PhantomReference调用get方法获取的值是空

(2)在子线程中,调用referenceQueue.remove()方法来获取队列中的数据,如果队列中没有数据,则会阻塞;虚引用被回收时,虚引用的对象会加入到ReferenceQueue中,阻塞停止,继续向下执行。

二、弱引用

弱引用和虚引用有一定的区别。

(1)虚引用需要和ReferenceQueue配合使用,而弱引用则不需要。

(2)虚引用通过get()获取的对象为空,而弱引用则获取的是对象

所以使用弱引用可以很好的避免内存泄漏的问题。如果你想随时使用某个生命周期短的对象,又不影响它的回收,建议使用弱引用

public class WeakTest {
    ReferenceQueue<Object>referenceQueue = new ReferenceQueue<>();
    Object object = new Object();
    WeakReference<Object>weakReference = new WeakReference<>(object,referenceQueue);

    public void start(){
        new Thread(()->{
            System.out.println("reference.get()="+weakReference.get());
            WeakReference<Object>reference = null;
            try {
                reference = (WeakReference<Object>) referenceQueue.remove();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("弱引用对象:"+reference);
            System.out.println("reference.get()=:"+reference.get());
        }).start();
    }

    public static void main(String[] args) throws InterruptedException {
        WeakTest test = new WeakTest();
        test.start();
        test.object = null;
        Thread.sleep(5000);
        System.out.println("启动gc");
        System.gc();
        Thread.sleep(5000);
    }
}

输出如下:

reference.get()=java.lang.Object@67f9d772
======================
弱引用对象:java.lang.ref.WeakReference@693e25fd
reference.get()=:null

从输出结果中,我们可以看到,在Object对象回收之前,reference.get方法返回了Object的引用地址;回收之后,reference.get方法返回的是null 

三、软引用

软引用的用法和弱引用的用法基本一样,不过不能像上面的代码一样做测试,因为只有当堆空间不够时,软引用才会被回收,所以我们需要模拟堆空间不足的情况:第一、修改堆空间的大小;第二不断创建垃圾对象

如图,-Xms20m表示堆空间的初始大小,-Xmx20m表示堆空间的最大值。

public class SoftTest {
    ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
    Object object = new Object();
    SoftReference<Object>softReference = new SoftReference<>(object,referenceQueue);

    public void start(){
        new Thread(()->{
            System.out.println("reference.get()="+softReference.get());
            SoftReference<Object> reference = null;
            try {
                reference = (SoftReference<Object>) referenceQueue.remove();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("软引用对象:"+reference);
            System.out.println("reference.get()=:"+reference.get());
        }).start();
    }

    /**
     * 创建垃圾
     */
    public static void createGarbage(){

        List<byte[]> list = new LinkedList<>();
        for (int i = 0; i <100; i++) {
            list.add(new byte[1024*1024]);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SoftTest test = new SoftTest();
        test.start();
        test.object = null;
        Thread.sleep(5000);
        System.out.println("======================");
        System.gc();
        createGarbage();
        Thread.sleep(5000);
    }
}

createGarbage方法在不断创建垃圾对象,当内存不足时,就会对软引用进行回收了,输出如下:

reference.get()=java.lang.Object@706fe943
======================
软引用对象:java.lang.ref.SoftReference@7ea8093e
reference.get()=:null

当然这段代码会由于堆空间不足而崩溃 

四、内存分析工具

Android Studio有很好的分析内存及CPU分析工具Profile

和应用关联之后,会有如下的图展示

我们主要分析内存,所以点击上图红色框的部分,会变成如下的表现形式

关于Profile的使用,可以百度,可以对应用做出各种情况的分析。这里我说的是另外一种工具,可以和Profile配合使用,叫做MemoryAnalyzer。百度搜索,自行下载~

如何配合使用呢。

1.导出Profile某个时间段的内存数据

点击红色框的按钮,会出现黑色框的内容。在黑色框内容中,右键点击Export,保存。

2.修改导入的数据文件格式

进入到SDK路径———>platform-tools目录中,找到hprof-conv.exe文件。然后进入到cmd模式,或者加入到环境变量中。

#src_1.hprof:表示刚刚保存的内存数据文件
#dist_1.hprof:表示转换的内存数据文件
hprof-conv -z src_1.hprof dist_1.hprof

3.使用MemoryAnalyzer打开文件

点击File-->Open Heap Dump找到刚刚转换的文件

打开后基本如下,我们可以在下图的红色框部分寻找自己需要的数据,可以自己点击尝试阅读,或者百度一下相关的教程吧。

本篇文章到此结束,之后还会有第二篇内存优化的文章。欢迎提问,欢迎纠错!

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值