假设我有一个这样的代码:
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被首先膨胀时发生),静态变量就应该始终存在,然后一直保留在应用程序本身被终止之前.如果是这样,那么什么可以防止Bitmap和Canvas对象保持打开状态并填满堆?
我曾经看到的唯一的声明反复表明,你不能泄漏静态上下文,就像我在构造函数中显示的一样,但它永远不会超出这一点.这是真的唯一不能做的事吗?
解决方法
就像你的例子
public class SomeClass extends SurfaceView { private static Context myContext; public MyInnerClass(Context context){ myContext = context; // This is bad. } }
这确实很糟糕即使不存在对SomeClass的引用(例如,显示您的自定义SurfaceView的Activity已经结束),对Context的静态引用(以及SomeClass中的任何其他静态变量/常量)仍然存在,您可以认为它们都是泄漏的,因为它是不可能的垃圾收集上下文等.如果你有一个常规变量引用的东西,那么一旦包含该变量的实例没有更多的引用,整个实例包括对其他事情的引用可以而且将被垃圾回收Java甚至可以处理循环参考罚款.
对于常量,您希望发生这种情况,它通常不会坏,因为它们占用的常量和内存量不大.此外,常量不(不应该)引用占用大量内存的其他实例,如Context或Bitmap.
除了通过静态变量创建内存泄漏的可能性之外,如果您不希望在同一时间只对所有实例都只有一件事情,那么也可能会产生问题.例如,如果将SurfaceView的Bitmap保存在静态变量中,则不能有两个不同的图像.即使两个SurfaceViews不同时显示,您也可能遇到问题,因为每个新的实例都可能会覆盖旧图像,如果返回到另一个SurfaceView,则会意外显示错误的图像.我几乎肯定你不想在这里使用静态.
事实上,你的内部类是一个静态类并不意味着你必须使用静态变量 – 它只是意味着它的行为更像一个静态方法,因为它不能使用实例变量(不是静态的)你的班.
为了避免内存泄漏,您根本不应该使用静态变量.除非你做特殊的事情(例如计数一个类的实例),否则不需要使用它们.常数很好