关于内存泄漏和通用方法

时间:2016-09-19 07:55:27

标签: java android generics memory-leaks static

在我的应用中哪些更好用?

public class NetworkCheck {

    Context context;

    public NetworkCheck(Context context) {
        this.context=context;
    }

    public boolean isNetworkConnected() {
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        return cm.getActiveNetworkInfo() != null;
    }
}

...    

if(new NetworkCheck(this).isNetworkConnected()){
    //statement
}

对于上面的那个,我每次必须使用它的方法时都要创建堆内存。当它的作用域结束时它的堆内存将被销毁(意味着大括号结束)......

可替换地。

public class NetworkCheck {

    public static boolean isNetworkConnected(Context context) {
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        return cm.getActiveNetworkInfo() != null;
    }
}

...

if(NetworkCheck.isNetworkConnected(){
    //statement
}

对于这个,我不必创建任何堆内存。我读了很多文章,人们都说创建一个静态变量,方法导致应用程序中的内存泄漏。

请帮助我创建以下方法的Genric getLocalData() .....

 public static <T> void saveLocalData(Context context, String key, T value) {
        SharedPreferences prefs = context.getSharedPreferences(
                "Qikqrup", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = prefs.edit();
        if (value instanceof String)
            editor.putString(key, (String) value);
        else if (value instanceof Boolean)
            editor.putBoolean(key, (Boolean) value);
        else if (value instanceof Integer)
            editor.putInt(key, (Integer) value);
        editor.commit();
    }

6 个答案:

答案 0 :(得分:5)

第二种情况不能被打败,因为它是最严重的。

在第一种情况下,只要NetworkCheck对象存在,Context对象就会保持活动状态。还有第二个对象(NetworkCheck)。

然而:

  • 其使用受到限制,对象将迅速超出范围并被垃圾收集。因此,效果与我们周围的粒子和反粒子的自发创造一样显着。
  • 在其他情况下,构造函数和调用的分离,也许许多调用可能证明是有用的。

关于:

public static <T> void saveLocalData(Context context, String key, T value)

没用,Object会更好。实际上null不会被捕获。通常,此函数具有部分域:并非所有类都可以。再次检索该值将是猜测工作。

使用运行时信息可能会这样做。

public static <T> void saveLocalData(Context context, String key, Class<T> type, T value)
public static <T> T loadLocalData(Context context, String key, Class<T> type)

Java有一个 Serializable 接口,也可以使用。

public static <T> void saveLocalData(Context context, String key, Serializable value)

然后在存储时收到对象。您需要阅读有关该主题的内容。

答案 1 :(得分:4)

saveLocalData()方法中,不一定有内存泄漏,但可能内存泄漏,具体取决于您使用它的方式。例如,采取这个:

for( long i = 0;  i < Long.MAX_VALUE;  i++ )
{
    String name = String.valueOf( i );
    saveLocalData( context, name, i );
}

此循环将继续向地图添加值,直到内存不足为止。但是任何集合都可能发生同样的情况,而不仅仅是地图,并且无论您的集合是静态分配还是可以发生。使用静态集合比使用非静态集合稍微容易一些,因为可能非静态集合可能超出范围并被垃圾收集,而静态集合通常注定永远保留。

然而,这句话并不是绝对的:

  • 一方面,非静态集合可以通过被静态对象引用而非常容易地永久锚定到内存中,同时:

  • 另一方面,静态地图可以被明确地释放和重新分配,或者由一个不希望它变得太大的细心程序员清除。

为了编写getLocalData(),您需要按如下方式声明:

public static <T> T getLocalData( Context context, String key, Class<T> classOfValue )

并按如下方式调用它:

String name = MyClass.getLocalData( context, "Name", String.class );
在函数中,您将需要执行以下操作:

if( classOfValue == String.class )
    return editor.getString( key );
...

您的两个版本的NetworkCheck和您对每个版本的预期用法大致相同,在选择其中一个或另一个之间没有太大的收获或松散。执行new NetworkCheck(this)表示冗余内存分配,但正如您已经了解的那样,此内存可以非常快速地进行垃圾收集,因此不会造成任何损坏。

答案 2 :(得分:3)

我建议在这种情况下使用静态方法版本,因为创建一个新对象只是为了检查连接性。

&#34;静态方法只是方法,它们不存储在堆上,它们只是不能使用&#34;这个&#34; 。参数&#34;

About memory leaks and generic methods

答案 3 :(得分:3)

  

STATIC变量和方法导致MEMORY LEAK

这仅适用于类的静态字段,而不适用于方法。这是正确的,因为静态成员的值将存在于内存中,只要声明它们的类将驻留在内存中 - (或者,至少,只要您不将静态变量值设置为{{ 1}}允许GC回收内存) (顺便说一句:正确的术语是&#34;存储的实例导致长期内存消耗&#34;如果从未使用这些实例,它只会变成泄漏,否则它们变得长期有用术语记忆使用&#34;)。

至于静态方法 - 如果他们不在静态变量中存储他们正在创建的任何实例,那么这些实例将:

  1. 如果本地变量/非返回实例 - 在超出范围后尽快进行CG编辑(注意:&#34; asap&#34;不保证&#34;立即&# 34; - 这就是&#34;尽可能&#34;毕竟意味着

  2. 如果它们是返回值 - 它们只有在呼叫者释放它们之后才会被GC编辑(即不再&#34;存储&#34;它们将来用于它们)。对于返回的值,静态方法就像一个工厂&#39;:忽略特定的配置序列(假设比构造函数可以提供的更复杂),它们与创建的实例没有什么不同只是null

  3. 关于new ClassOfTheReturnedValue(...)public boolean isNetworkConnected()的关系:在您的使用示例中,它们与内存泄漏或创建实例的能力之间没有区别 GC-ed - 因为你的static public boolean isNetworkConnected()只是一个临时/局部变量,一旦超出范围就可以收集。
    两种方法的唯一区别:非静态真正创造了一个对象(因此CG在轨道上的工作量更多),而静态形式则没有。

    关于NetworkCheck check=new NetworkCheck(this);

    好吧,你发布它的方式是非常低级

    1. 如果使用除public static <T> void saveLocalData(Context context, String key, T value)StringBooleanIntegerLong之外的任何内容调用该方法,编译器将根据请求连接呼叫。在执行时间,您将花费不必要的类型检查(全部失败),仅在没有真正更改的情况下调用Float

    2. 关于类型安全性,您拒绝编译器在编译时执行类型检查以进行所有运行时类型检查的可能性。您的方法与editor.commit()没有区别 - 所有类型检查都延迟到运行时。泛型和普通对象之间的唯一区别是&#39;表单是:编译器将更加努力地编译泛型方法,但将达到与“对象”值相同的最终结果。方法

    3. 实现同样目标的最佳方法是放弃泛型的所有智能并使用普通的方法重载,如下所示:

      public static void saveLocalData(Context context, String key, Object value)

      以上:

      1. 编译器可以验证该方法未使用不合理的类型值调用

      2. 代码是最佳的

      3. 毕竟,protected static SharedPreferences.Editor resolveEditor( Context context, String prefOwner ) { SharedPreferences prefs = context.getSharedPreferences( prefOwner, Context.MODE_PRIVATE ); return prefs.edit(); } public static void saveLocalData(Context context, String key, boolean value) { SharedPreferences.Editor editor = resolveEditor(context, "sushildlh"); editor.putBoolean(key, value); editor.commit(); } public static void saveLocalData(Context context, String key, int value) { SharedPreferences.Editor editor = resolveEditor(context, "sushildlh"); editor.putInt(key, value); editor.commit(); } public static void saveLocalData(Context context, String key, String value) { SharedPreferences.Editor editor = resolveEditor(context, "sushildlh"); editor.putString(key, value); editor.commit(); } // etc 确实有理由不实施普遍的SharedPreferences.Editor - 是什么让你觉得你可以从外面做得更好 ?如果可能的话,我认为void putValue<T>(T value)的作者会在他们的实现中做到这一点。

答案 4 :(得分:2)

saveLocalData()方法不会导致任何内存泄漏,因为您没有阻止任何超过其生命周期的引用。

使用活动背景时,您应该注意以下几点:

  

你不应该在课堂上使用活动上下文,因为它可以活得更久   活动的生命周期。

例如:不要在数据库助手类或单例中使用活动上下文。

关于NetworkCheck,class2更好,因为isNetworkConnected()方法是一种实用工具方法,它不代表任何NetworkCheck状态。

<强>优点:

  1. 提高了性能,因为您没有实例化额外的对象。

  2. 不依赖于实例创建

  3. 可以在整个应用程序中轻松使用(在执行网络操作的不同类中)
  4. 将使代码更易于理解
  5. 缺点:

    1. 无法轻易模拟单元测试。

答案 5 :(得分:-1)

public class AppStatus {

private static AppStatus instance = new AppStatus();
static Context context;
ConnectivityManager connectivityManager;
boolean connected = false;

public static AppStatus getInstance(Context ctx) {
    if (ctx != null)
        context = ctx.getApplicationContext();
    return instance;
}

public boolean isOnline() {
    try {
        connectivityManager = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);

        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
        connected = networkInfo != null && networkInfo.isAvailable() &&
                networkInfo.isConnected();
        return connected;


    } catch (Exception e) {
        System.out.println("CheckConnectivity Exception: " + e.getMessage());
        Log.v("connectivity", e.toString());
    }
    return connected;
 }
}

要检查申请状态是否在线,请通过

进行检查
if ("package Name".AppStatus.getInstance(getActivity()).isOnline()) {}