android内存泄露:2、非静态的内部类错误使用_情形2

目录

一、前言

二、非静态的内部类错误使用-情形二

情形二:在Activity中,使用单例工厂类引用 Activity内部类

1、新建一个 Module,写主界面 MainActivity,布局 activity_main

2、写业务逻辑

3、效果展示

4、解决方案


一、前言

上篇文章我们介绍了:LeakCanary内存泄漏检测库、内存泄露_内存溢出_内存抖动、非静态的内部类错误使用以及解决方式,详细可参考博文:原创 android内存泄露:1、LeakCanary内存泄漏检测库、内存泄露_内存溢出_内存抖动、非静态的内部类错误使用,这篇文章我们将介绍:非静态的内部类错误使用-情形二

二、非静态的内部类错误使用-情形二

情形二:在Activity中,使用单例工厂类引用 Activity内部类

1、新建一个 Module,写主界面 MainActivity,布局 activity_main

MainActivity

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

    }

    public void innerClass(View view) {
        startActivity(new Intent(MainActivity.this,InnerClassActivity.class));
    }


}

activity_main

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    tools:ignore="MissingConstraints">


    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="innerClass"
        android:text="非静态内部类的错误使用-User" />

</androidx.constraintlayout.widget.ConstraintLayout>

2、写业务逻辑

工具类 UserUtils 

public class UserUtils {
    private static InnerClassActivity.User sUser;

    public static void setsUser(InnerClassActivity.User user) {
        sUser = user;
    }

}

InnerClassActivity

public class InnerClassActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_inner_class);

        //创建的非静态内部类User对象,对外部类(Activity)有隐式的强引用,
        //同时该内部类对象又永久被UserUtils静态变量给引用上了,
        //从而导致GC想回收该activity的堆内存,发现sUser还在引用,GC无法回收
        UserUtils.setsUser(new User("张三"));

    }

    class User{
        private String username;

        public User(String username){
            this.username = username;
        }
    }


}

3、效果展示

使用LeakCanary测试的结果如下:

4、解决方案

/**
 * 如果Activity中有非静态的内部类,我们创建了这个类的实例对象,
 * 但是我们把这个实例对象赋值给了一个单例工厂类,导致该内部类对象的生命周期永远都被引用,
 * 同时该对象又引用了Activity,那么就导致了Activity的内存泄露。
 */

解决方式:只需要将内部类User类改为静态内部类即可

静态类对象一旦被jvm(虚拟机)加载,一般是不会被移除掉的,

除非这个虚拟机是我们自定义的虚拟机,也就是我们自己去定义一个类加载器,它继承于ClassLoader,

当我们自定义的类加载器被卸载掉后,所加载的静态类对象才会被移除掉。

默认情况下,我们都使用系统自带的类加载器,它加载的静态对象,是不会被GC回收掉的。

所以让User成为静态类,静态类属于字节码级别的,不再是Activity里面的内部类

当然用静态会有影响

因为这个对象是静态的,那么这个类被加载了,就不会被GC回收释放掉。

但最起码它不会影响 Activity的生命周期,不会影响GC去回收我们这个Activity,

所以应该去慎用,内部类我们也应该去慎用,

这个就需要我们去平衡他们相互之间的关系了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

被开发耽误的大厨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值