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

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

问题描述

我一直在研究在创建视图时防止上下文/活动内存泄漏的最佳实践,但我似乎无法找到关于类中静态字段允许或不允许的明确答案.

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

我对 JVM 实际上认为 MyInnerClass 的 ClassLoader 有点困惑.从技术上讲,由于它是 SurfaceView 对象,因此一旦应用程序实例化 MyInnerClass 一次(这发生在 View 第一次膨胀时),似乎静态变量应该始终存在,然后保持在那里,直到应用程序本身终止.如果是这种情况,是什么阻止 Bitmaps 和 Canvas 对象也保持打开状态并填满堆?

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?

推荐答案

在 Java/Android 中,static 变量或常量不会被垃圾收集.一旦通过类加载器加载了包含它的类,它就会留在那里.类加载器对于您的应用程序中的所有类来说总是相同的,并且它具有对所有类的静态引用(例如 MyInnerClass.class).由于类加载器不会消失,您的类也不会这样做,因为它们被引用 &因此不可垃圾回收.

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.

就像你的例子

public class SomeClass extends SurfaceView {
  private static Context myContext;

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

这确实很糟糕.即使不存在对 SomeClass 的引用(例如,显示您的自定义 SurfaceViewActivity 已经结束)对 Context<的静态引用/code>(以及 SomeClass 中的任何其他 static 变量/常量都将保留.您可以认为所有这些都已泄漏,因为不可能对该 Context 进行垃圾收集 等.如果你有一个常规变量引用某个东西,那么一旦包含该变量的实例不再引用它,整个实例包括它对其他东西的引用就可以并且将被垃圾收集.Java甚至可以处理循环引用很好.

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 consider 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.

对于您希望发生这种情况的常量,它通常还不错,因为常量的数量和它们占用的内存量并不大.此外,常量不会(不应)引用其他占用大量内存的实例,例如 ContextBitmap.

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.

除了通过静态变量造成内存泄漏的可能性之外,如果您不想同时为所有实例只有一个东西,您也可能会产生问题.例如,如果您将 SurfaceViewBitmap 保存在 static 变量中,则不能有两个不同的图像.即使两个 SurfaceView 没有同时显示,您也可能会遇到问题,因为每个新实例可能会覆盖旧图像,如果您返回到另一个 SurfaceView> 你意外地显示了错误的图像.我几乎可以肯定您不想在这里使用 static.

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.

你的内部类是一个 static class 的事实并不意味着你必须使用静态变量 - 它只是意味着它的行为更像是一个 static 方法,因为它不能在你的类中使用实例变量(那些不是 static 的).

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.

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

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