Android:静态字段和内存泄漏
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11908039/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android : Static Fields and Memory Leaks
提问by SeaNick
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?
我对 JVM 实际上认为 MyInnerClass 的 ClassLoader 有点困惑。从技术上讲,由于它是 SurfaceView 对象,因此一旦应用程序实例化 MyInnerClass 一次(这发生在 View 第一次膨胀时),似乎静态变量应该始终存在,然后保持在那里,直到应用程序本身终止。如果是这种情况,是什么阻止位图和画布对象也保持打开状态并填满堆?
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?
我一遍又一遍地看到的唯一声明是你不能像我在构造函数中展示的那样泄漏静态上下文,但它永远不会超出这一点。这真的是你唯一不能做的吗?
回答by zapl
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.
在 Java/Android 中,static
变量或常量不会被垃圾收集。一旦通过类加载器加载了包含它的类,它就会留在那里。类加载器对于您的应用程序中的所有类来说总是相同的,并且它的类加载器对您的所有类(例如MyInnerClass.class
)具有静态引用。由于类加载器不会消失,您的类也不会这样做,因为它们被引用,因此不可垃圾收集。
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 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.
那确实很糟糕。即使没有对SomeClass
存在的引用(例如Activity
,表明您的自定义SurfaceView
已结束),对Context
(以及任何其他static
变量/常量的静态引用SomeClass
将保留。您可以认为所有这些都已泄漏,因为不可能进行垃圾收集Context
等。如果你有一个常规变量引用某物,那么一旦包含该变量的实例不再引用它,整个实例包括它对其他事物的引用就可以并且将被垃圾收集。Java甚至可以很好地处理循环引用。
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
.
对于常量,您希望这种情况发生并且通常还不错,因为常量的数量和它们占用的内存量并不大。常量也不会(不应该)引用其他占用大量内存的实例,例如Context
或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 SurfaceView
s 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.
除了通过静态变量创建内存泄漏的可能性之外,如果您不想同时为所有实例只有一个东西,您也可能会产生问题。例如,如果你保存Bitmap
你的SurfaceView
一个static
变量,你不能有两个不同的图像。即使两个SurfaceView
s 没有同时显示,您也可能会遇到问题,因为每个新实例可能会覆盖旧图像,如果您返回另一个实例,您会SurfaceView
意外地显示错误的图像。我几乎可以肯定你不想在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.
您的内部类是 a 的static class
事实并不意味着您必须使用静态变量 - 它只是意味着它的行为更像是一种static
方法,因为它不能使用static
您的类中的实例变量(不是)。
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.
为了避免内存泄漏,您根本不应该使用静态变量。除非你做特殊的事情(例如计算类的实例),否则没有必要使用它们。常数没问题。
回答by IgorGanapolsky
This article talks about mutable static fields: http://javabook.compuware.com/content/memory/problem-patterns/memory-leaks.aspx. Basically, avoid them and use constants instead.
本文讨论可变静态字段:http: //javabook.compuware.com/content/memory/problem-patterns/memory-leaks.aspx。基本上,避免它们并使用常量代替。