安卓:静态字段和内存泄漏 [英] Android : Static Fields and Memory Leaks

查看:194
本文介绍了安卓:静态字段和内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在学习上为preventing上下文/活动内存的最佳实践泄漏的创建视图的时候,我似乎无法找到什么或不允许一个肯定的答案,当谈到静态字段在课堂上。

让我们说我有这种形式的code:

 公共类MyOuterClass延伸活动{
   私人MyInnerClass;
   MyInnerClass =(MyInnerClass)findViewById(小于这里XML调用>);
   MyInnerClass.myXInt = 3;

   //的onCreate(),onResume()等

   公共静态类MyInnerClass扩展了SurfaceView实现Runnable {
      //安全变量?
      私有静态诠释myXInt,myYInt;
      私有静态布尔myBoolean;
      //潜在的安全吗?
      私有静态帆布myCanvas;
      //肯定不好。
      私有静态语境myContext;

      公共MyInnerClass(上下文的背景下){
         myContext =背景; // 这不好。
      }
   }
}
 

我略有困惑什么的JVM实际考虑的ClassLoader的MyInnerClass。从技术上讲,因为它是一个SurfaceView对象,这似乎是一个静态变量应该始终存在,一旦应用程序实例化MyInnerClass一次(当查看第一次充气而发生),然后继续留在那里,直到自己被终止应用程序。如果是这样的话,有什么prevents位图和帆布残留开放以及与填补了堆中的对象?

我看到过一遍又一遍地重复的唯一说法是,你不能漏静态上下文就像我已经展示在构造函数中,但它永远不会超越这一点。那是真正的唯一的事情你不能做?

解决方案

在Java / Android的一个静态变量或常量不会被垃圾收集

。这只是一次保存它的类是通过类加载器加载在那里停留。类加载器是AFAIK总是相同的应用程序,它的一个具有静态引用所有的类内的所有类(以如 MyInnerClass.class )。由于类加载器不走你的类就不会做,要么因为他们被引用和放大器;因此不垃圾的收藏价值。

就像在你的例子

 公共类SomeClass的延伸SurfaceView {
  私有静态语境myContext;

  公共MyInnerClass(上下文的背景下){
     myContext =背景; // 这不好。
  }
}
 

这确实是坏的。即使没有提及 SomeClass的的存在(如活动即表明您自定义的 SurfaceView 结束)的静态参考上下文(以及任何其他静态变量/常量 SomeClass的将保持不变。你可以认为所有的人泄露,因为它是不可能的垃圾收集上下文等,如果您有一个常规的变量引用的东西再一次包含变量它没有更多的参考实例整个实例包括其对其他事物能够而且将会垃圾回收。Java的,甚至可以处理循环引用的罚款。

有关的常数,你想这样的事情发生,这是通常不坏,因为常量的数量和记忆它们占用不是很大的数额。此外常量不(应该)引用占用大量内存的如上下文位图其他实例。

除了创建内存的可能性,通过静态变量泄漏,你也可以创建问题,如果你不希望只为在同一时间的所有实例的一件事情。例如,如果你保存位图 SurfaceView 在一个静态变量,你不能有两个不同的图像。即使两个 SurfaceView s的同时不会显示你可能会遇到问题,因为每一个新的实例,可能会覆盖旧形象,如果你回到其他 SurfaceView 你意外地显示出​​错误的图像。我几乎可以肯定,你不想使用静态在这里。

事实上,你的内部类是静态类并不意味着你必须使用静态变量 - 它只是意味着它更像一个静态的方法,因为它不能使用实例变量(那些没有静态)的类。

为避免你根本不应该在所有使用静态变量的内存泄漏。有没有必要使用它们,除非你做特别的东西(一类的如计算实例)。常量是很好。

I've been studying up on best practices for preventing Context/Activity memory leaks when creating views, and I can't seem to find a definite answer on what is or is not allowed when it comes to static fields in classes.

Let's say I have a code of this form:

public class MyOuterClass extends Activity{
   private MyInnerClass;
   MyInnerClass = (MyInnerClass) findViewById(<XML call here>);
   MyInnerClass.myXInt = 3;

   // onCreate(), onResume(), etc.

   public static class MyInnerClass extends SurfaceView implements Runnable{
      // Safe variables?
      private static int myXInt, myYInt;
      private static boolean myBoolean;
      // Potentially safe?
      private static Canvas myCanvas;
      // Definitely bad.
      private static Context myContext;

      public MyInnerClass(Context context){
         myContext = context;        // This is bad.
      }
   }
}

I am slightly confused on what the JVM actually considers the ClassLoader for MyInnerClass. Technically, since it is a SurfaceView object, it seems like the static variables should always exist once the application has instantiated MyInnerClass one time (which happens when the View is first inflated), and then remain there until the application itself is terminated. If that is the case, what prevents Bitmaps and Canvas objects from remaining open as well and filling up the heap?

The only statement I ever see repeated over and over is that you can't leak static Context like I have shown in the constructor, but it never goes beyond that. Is that really the only thing you can't do?

解决方案

In Java/Android a static variable or constant will not be garbage collected. It just stays there once the class that holds it is loaded via a class loader. The class loader is afaik always the same for all classes inside your app and its the one that has static references to all your classes (to e.g. MyInnerClass.class). Since the class loader does not go away your classes won't do that either since they are referenced & therefore not garbage collectable.

Like in your example

public class SomeClass extends SurfaceView {
  private static Context myContext;

  public MyInnerClass(Context context){
     myContext = context;        // This is bad.
  }
}

That is indeed bad. Even if no reference to SomeClass exists (e.g. the Activity that showed your custom SurfaceView has ended) the static reference to the Context (and any other static variable / constant in SomeClass will remain. You can considers all of them leaked since it is not possible to garbage collect that Context etc. If you have a regular variable reference something then once the instance that contains that variable has no more references to it the whole instance including its references to other things can and will be garbage collected. Java can even handle circular references fine.

For constants you want that to happen and it is usually not bad since the amount of constants and the amount of memory they occupy is not large. Also constants don't (should not) reference other instances that take up large amounts of memory like Context or Bitmap.

Besides the possibility to create memory leaks through static variables you may also create problems if you don't want to have only a single thing for all instances at the same time. For example if you save the Bitmap of your SurfaceView in a static variable you can't have two different images. Even if the two SurfaceViews are not displayed at the same time you could run into problems since each new instance will probably overwrite the old image and if you go back to the other SurfaceView you unexpectedly show the wrong image. I am almost sure you don't want to use static here.

The fact that your inner class is a static class does not mean that you have to use static variables - it just means that it behaves more like a static method since it can't use the instance variables (the ones that are not static) in your class.

To avoid memory leaks you simply should not use static variables at all. There is no need to use them unless you do special stuff (e.g. counting instances of a class). Constants are fine.

这篇关于安卓:静态字段和内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆