简体   繁体   English

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

[英]Memory allocation difference between Singleton vs static final instance

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;
    }
}

Here in this approach whenver my application exits then I can release memory by calling releaseMemory() so that myActivity instance will not be leaked. 在这种方法中,只要我的应用程序退出,我就可以通过调用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;
    }
}

In this approach as MyClass instance is final I can't make it null instead I can make individual variables as null. 在这种方法中,由于MyClass实例是最终的,因此我不能将其设置为null,而可以将单个变量设置为null。

So is My understanding correct or am I missing anything respective to memory leaks? 那么我的理解是正确的还是我缺少与内存泄漏有关的任何内容?

First question, why do you need to keep a reference on an Activity object ? 第一个问题,为什么需要在Activity对象上保留引用?

For most usage you just need a Context object. 对于大多数用法,您只需要一个Context对象。 So if you want to avoid leaking your Activity take the habit to do the following by replacing : 因此,如果您想避免泄漏您的Activity请养成以下习惯:

private MyActivity myActivity;

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

with: 与:

private Context myContext;

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

Since Activity is an implementation of Context, your code should keep working. 由于Activity是Context的实现,因此您的代码应保持正常运行。 The method getApplicationContext() will always return an Application Context which you can leak all you want. 方法getApplicationContext()将始终返回一个应用程序上下文,您可以泄漏所有想要的内容。

Now if an Application Context is not enough and you really need an Activity object (if you need to start other Activity without creating a new task for exemple), first ask yourself why you can't do that in your Activity class directly. 现在,如果应用程序上下文还不够,并且您确实需要一个Activity对象(如果您需要启动其他Activity而不创建示例新任务),请首先问问自己为什么不能直接在Activity类中做到这一点。 If you can't, then maybe you have taken bad decision regarding your code architecture. 如果不能,则可能是您在代码体系结构方面做出了错误的决定。

If you really need to store Activity object in other object (singleton or not), please remember that activities have a lifecycle, and you need your Activity to notify your MyClass that it will be no longer available (if you don't, and you forget to call releaseMemory(), then your Activity will leak when it goes to background) : 如果您确实需要将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;
    }
}

In case your MyClass is also a Fragment , you can do the job of setting and releasing your Activity in the methods onAttach() and onDetach() (those methods are automaticaly called by Android, so you don't need to try to call them in your Activity ). 如果您的MyClass也是Fragment ,则可以在onAttach()onDetach()方法中设置和释放Activity (这些方法由Android自动调用,因此您无需尝试调用它们)在您的Activity )。

Finally, I would advise against your first code sample, because even if you call your method releaseMemory() and ensure you have no reference left in your object A , there is nothing you can do to ensure an object B doesn't still have a reference to your class MyClass . 最后,我建议不要使用第一个代码示例,因为即使调用方法releaseMemory()并确保对象A没有剩余引用,也无法采取任何措施来确保对象B仍然没有对象A引用您的类MyClass

final field can't be modified. 最终字段无法修改。 that's why final modifier exists. 这就是存在final修饰符的原因。

second version of your singleton is better regarding conccurency. 您的单例的第二个版本在一致性方面更好。 but it will be never gc'ed until you close the app. 但除非您关闭应用程序,否则它将永远不会被gc'ed。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM