4、常见内存泄漏
这是一个老生常谈的一个问题了,但我还是先对Java中的内存泄漏做一个定义:
Java中的内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。
在C++中,内存泄漏的范围更大一些。有些对象被分配了内存空间,然后却不可达,由于C++中没有GC,这些内存将永远收不回来。在Java中,这些不可达的对象都由GC负责回收,因此程序员不需要考虑这部分的内存泄露。
对于Java中的内存泄漏,我总结为三点:static、线程 和 系统(外部)资源申请。
对于JVM内部而言,它的垃圾回收机制真的做的非常不错,我总觉得Java的出现是程序员的一次体力解放,大家再也不用去关心那个让RD们睡不好觉的指针问题;而JVM内部的内存泄漏,追究起原因来,我觉得(瞎估的)90%是static静态变量引起的、10%是while(true)的线程造成的,大家想一下,我们平时发现的内存泄漏,是不是大都是注册了监听没释放,或者是声明了一个大对象的static为了方便传递数据,结果忘了置空;对于static这样的变量,我们声明时要非常小心,我的意见是,不是非常必要的情况下,能不用尽量不要用。
外部资源申请一般指的是打开一些文件、设备、数据库等,这些系统都会给我们提供一些开销,如果我们没能及时关闭掉这些设备,则会造成不必要的内存开销。
Android上的内存泄漏会更具体一些,有些也会很隐蔽,我们来具体分析一下,这也是每个Android程序员面试都会考到的一个题。
(1)activity泄漏
这是我们平时最关心的泄漏,因为Activity在Android的四大组件中持的有资源最多,一个Activity没回收,会导致它里面的无数个View都无法被回收到。
<1>在需要Context的地方传入Activity,导致被静态变量持有,这种情况大家应该碰到的很多。
public class AppManager {
private static AppManager instance;
private Context context;
private AppManager(Context context) {
this.context = context;
}
public static synchronized AppManager getInstance(Context context) {
if (instance == null) {
instance = new AppManager(context);
}
return instance;
}....
// 使用时
AppManager am = AppManager.getInstance(activity);
上面这种情况,activity就被静态变量instance持有了,除非appmanager这个单例释放了。
这种情况有两个解决办法:
1、AppManager am = AppManager.getInstance(activity.getApplicationContext()); // 不建议
2、private AppManager(Context context) {
this.context = context.getApplicationContext();
}
建议使用第二种方法,因为这是从根上进行的解决,而第一种方法是需要调用者来保证解决,这种方法很不靠谱,而且从严格意义上说,调用都使用的根本没错,他传进去的Activity就是一个Context。
&