Android:内存泄漏检查内存优化

news/2024/6/17 3:42:39 标签: android, LeakCanary, 内存优化, 内存泄漏

3.17Android优化

    手机移动设备的内存是有限的,需要避免内存泄漏,优化内存使用。

1.java中四种引用类型

    强引用、软引用、弱引用、虚引用。

    强引用:使用类构造方法,创建对象,当内存超出了,也不会释放对象所占内存空间;

    String str = new String(‘1223’);

    切断引用str=null;

    软引用:当内存不足时,会释放对象所占内存空间

    SoftReference<String> softReference = new SoftReference<String>(str);

    切断引用softReference.clear()

    弱引用:只要系统产生GC(垃圾回收),会释放对象所占空间

    WeakReference<String> weakReference = new WeakReference<String>(str);

    切断引用System.gc(),调用垃圾回收

    虚引用:判断对象是否已经被释放

    PhantomReference<String> phantomReference = new PhantomReference<String)(str);

2.LeakCanary使用

    LeakCanary是一个内存泄漏检查的开源项目。

    网址:https://square.github.io/leakcanary/

1.添加LeakCanary到build.gradle

找到build.gradle(Module:app)文件添加:

dependencies {

  // debugImplementation because LeakCanary should only run in debug builds.

  debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.2'

}

执行程序,设置过滤器Log tag:LeakCanary,可以看到:

2.常见内存泄漏类型

    内存泄漏:在java运行过程中,内存泄漏是一种编程错误,使得应用程序保留不再需要的对象的引用。结果,无法回收该对象分配的内存,最终导致OutOfMemoryError。例如:一个Activity在调用其onDestroy方法后,就不再使用。但是在静态字段中保存对Activity的引用,阻碍了GC对内存的垃圾回收。

    大多数内存泄漏是由与对象生命周期相关的错误引起的。 以下是一些常见的Android错误:

    Fragment的onDestroyView方法中没有清除不再使用的View;

    Activity的Context储存为对象的字段,由于配置原因不能重新创建该对象;

    注册监听器、广播、RxJava订阅后,在其生命周期结束后忘记取消注册;

内部类导致内存泄漏

    内部类示例会隐式持有外部类引用。内部类执行线程耗时操作时,外部类Activity关闭,内部类会继续持有外部类引用,调用外部类方法,但是Activity已经无用,应该回收,这样会引起内存泄漏

示例:

创建内部类MyThread,执行一个耗时操作,Activity点击按钮触发耗时操作,在执行过程中将退出Activity,导致内存泄漏

public class MainActivity extends AppCompatActivity {
    private Button button1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button1=findViewById(R.id.btn1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startTask();
            }
        });
    }

    //执行耗时操作
    public void startTask(){
        MyThread myThread=new MyThread();
        myThread.start();
    }
    private class MyThread extends  Thread{
        @Override
        public void run() {
            for(int i=0;i<100;i++){
                //耗时操作
                SystemClock.sleep(1000);
            }
        }
    }
}

 

在通知栏可以看到LeakCanary弹出通知信息,点击可以查看详细信息。

在AndroidStudio的Logcat中也可以看到类似详细信息。

处理内部类内存泄漏:将内部类改为静态内部类,这样内部类将不再隐式持有外部类的引用,当然内部类也不能访问外部类非静态字段、方法。内部类可以通过弱引用来使用外部类非静态字段、方法,这样当GC时,不会出现内存泄漏

示例:

public class MainActivity extends AppCompatActivity {
    private Button button1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button1=findViewById(R.id.btn1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startTask();
            }
        });
    }

    //执行耗时操作
    public void startTask(){
        MyThread myThread=new MyThread(MainActivity.this);
        myThread.start();
    }
    //修改为静态内部类,不再隐式持有外部类引用
    private static class MyThread extends  Thread{
        //通过弱引用获取Activity中非静态字段、方法
        WeakReference<MainActivity> weakReference=null;
        public MyThread(MainActivity mainActivity){
            weakReference=new WeakReference<MainActivity>(mainActivity);
        }
        //获取外部类对象
        public void getOutObj(){
            //获取外部类对象
            MainActivity mainActivity=weakReference.get();
            //获取成功,通过外部类对象获取属性、方法
            if (mainActivity!=null){

            }
        }
        @Override
        public void run() {
            for(int i=0;i<100;i++){
                //耗时操作
                SystemClock.sleep(1000);
            }
        }
    }
}

内部类Handler导致内存泄漏

示例:在MainActivity中创建内部类Handler,创建startMessage方法,执行延迟发送message操作,当退出Activity时,也会出现内部类的内存泄漏。解决办法也是将内部类修改为静态或者创建对应的MyHandle


http://www.niftyadmin.cn/n/5372969.html

相关文章

XSS-Lab

1.关于20关的payload合集。 <script>alert(1)</script> "><script>alert(1)</script> onclickalert(1) " onclick"alert(1) "><a href"javascript:alert(1)"> "><a HrEf"javascript:alert…

Android java基础_类的继承

一.Android Java基础_类的继承 先封装一个persion类&#xff0c;在persion的基础上定义Student类&#xff0c;并基础persion类。 子类能访问父类的成员函数。 class Person {private int age;public void setAge(int age) {if (age < 0 || age > 200)age 0;else {thi…

【Java多线程案例】实现阻塞队列

1. 阻塞队列简介 1.1 阻塞队列概念 阻塞队列&#xff1a;是一种特殊的队列&#xff0c;具有队列"先进先出"的特性&#xff0c;同时相较于普通队列&#xff0c;阻塞队列是线程安全的&#xff0c;并且带有阻塞功能&#xff0c;表现形式如下&#xff1a; 当队列满时&…

【Java】学习笔记:关于java.sql;

Connection conn null; Connection&#xff1a;这是一个 Java 接口&#xff0c;表示与数据库的连接。在这里&#xff0c;conn 是一个 Connection 类型的变量。 conn&#xff1a;这是变量的名称&#xff0c;可以根据需要进行更改。通常&#xff0c;conn 被用作表示数据库连接的…

在gtkmm4 中检索子控件 (children)

文章目录 前言源代码 前言 gtkmm4.10已经没有控件的 get_children() 方法了但引进了observe_children() 但这个如其名字一样, 不能对子控件作修改 可以用它返回的对象.get_n_items() 获取子控件的数量还有如下的代替 get_first_child() : 如果只有一个child 则first与last返回…

Codeforces Round 923 (Div. 3) C. Choose the Different Ones(Java)

比赛链接&#xff1a;Round 923 (Div. 3) C题传送门&#xff1a;C. Choose the Different Ones! 题目&#xff1a; ** Example** ** input** 6 6 5 6 2 3 8 5 6 5 1 3 4 10 5 6 5 6 2 3 4 5 6 5 1 3 8 10 3 3 3 4 1 3 5 2 4 6 2 5 4 1 4 7 3 4 4 2 1 4 2 2 6 4 4 2 1 5 2 3 …

前端工程化面试题 | 03.精选前端工程化高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Nginx配置php留档

好久没有用过php了&#xff0c;近几日配置nginxphp&#xff0c;留档。 安装 ubunt下nginx和php都可以使用apt安装&#xff1a; sudo apt install nginx php8 如果想安装最新的php8.2,则需要运行下面语句&#xff1a; sudo dpkg -l | grep php | tee packages.txt sudo add-…