Singleton与静态最终实例之间的内存分配差异

时间:2016-09-30 16:10:40

标签: java android memory-leaks

public class MyClass {
    private static MyClass instance = null;
    private MyActivity myActivity;
    private Button button;

    public static MyClass getInstance(){
        if (instance == null){
            instance = new MyClass();
        }
        return instance;
    }

    private MyClass(){};

    public void initialize(MyActivity activity){
        myActivity = activity;
    }

    public void releaseMemory(){
        instance = null;
    }
}

当我的应用程序退出时,这种方法就在这里 我可以通过调用releaseMemory()来释放内存,以便myActivity 实例不会泄露。

public class MyClass {
    private static final MyClass instance = new MyClass();
    private MyActivity myActivity;
    private Button button;


    private MyClass(){};

    public void initialize(MyActivity activity){
        myActivity = activity;
    }

    public void releaseMemory(){
        instance = null; //Can't make it null
        //Can do for individual variables
        myActivity = null;
        button = null;
    }
}

在这种方法中,MyClass实例是final,我不能使它为null 相反,我可以将单个变量设为null。

我的理解是正确的还是我错过了与内存泄漏相关的任何内容?

2 个答案:

答案 0 :(得分:0)

第一个问题,为什么需要在Activity对象上保留引用?

对于大多数用法,您只需要一个Context对象。因此,如果您想避免泄露您的Activity,请习惯通过更换以下内容来执行以下操作:

private MyActivity myActivity;

public void initialize(MyActivity activity){
    myAcitivity = activity;
}

with:

private Context myContext;

public void initialize(Context context){
    myContext = context.getApplicationContext();
}

由于Activity是Context的一个实现,因此您的代码应该继续工作。方法getApplicationContext()将始终返回一个应用程序上下文,您可以泄漏所有内容。

现在,如果应用程序上下文不够,并且您确实需要一个Activity对象(如果您需要启动其他Activity而不为exemple创建新任务),请首先问问自己为什么不能直接在Activity类中执行此操作。如果你做不到,那么也许你对你的代码架构做出了错误的决定。

如果您确实需要将Activity对象存储在其他对象(单身或非单身)中,请记住活动有生命周期,您需要Activity通知您的MyClass它将不再可用(如果你没有,你忘记调用releaseMemory(),那么你的Activity将在它转到后台时泄漏):

public class MyActivity {

    MyClass myClass; // instance initialize somewhere in your code

    onPause() {
        myClass.setActivity(this);
    }

    onResume() {
        myClass.setActivity(null);
    }
}

public class MyClass {

    @Nullable Activity myActivity; // tha @Nullable annotation helps you remember to do null checks before using this field.

    public void setActivity(Activity activity) {
        myActivity = activity;
    }
}

如果您的MyClass也是Fragment,您可以在方法ActivityonAttach()中设置和发布onDetach()(这些方法是由Android自动调用的,因此您无需尝试在Activity中调用它们。

最后,我建议不要使用您的第一个代码示例,因为即使您调用方法releaseMemory()并确保您的对象A中没有任何引用,您也无法确保对象B仍然没有对您的班级MyClass的引用。

答案 1 :(得分:0)

最终字段无法修改。这就是最终修饰符存在的原因。

你的单身的第二个版本在conccurency方面更好。但在关闭应用程序之前,它永远不会被gc'ed。