一、内存泄漏(ACTIVITY_LEAK)
1、静态变量持有Activity对象,导致Activity无法释放
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
解决方法:杜绝静态变量持有activity
2、单例模式持有Activity对象,导致Activity无法释放
public class GameNotFreeFlowDialogActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FreeFlowUtil.getInstance().showMessageDialog(GameNotFreeFlowDialogActivity.this, FreeFlowUtil.FLAG_DOWNLOAD_MESSAGE, new FreeFlowDialog.FreeFlowClickListener() {
@Override
public void doClickEvent() {
final DownloadInfo info = getIntent()
.getParcelableExtra("downloadinfo");
AppClickActionUtils.launchGameCenterDialogActivity(getApplicationContext(), info);
finish();
}
@Override
public void cancelClickEvent() {
finish();
}
});
}
}
在GameNotFreeFlowDialogActivity.onCreate方法中调用了单例类FreeFlowUtil的showMessageDialog()方法,
其中FreeFlowUtil的showMessageDialog()方法中第一个参数需要传入Context类。
由于FreeFlowUtil类为单例模式,生命周期与JVM相同(与application相同),在FreeFlowUtil类创建了mChinaUnicomAlertDialog对象并传入了GameNotFreeFlowDialogActivity的Context,导致Context生命周期(GameNotFreeFlowDialogActivity的生命周期)同FreeFlowUtil相同,导致了泄漏问题。
解决方法:
方法一:不用单例模式
方法二:将Activity的Context改为Application的Context:getApplicationContext(),这样单例模式持有的就不是单个activity了
注意:不是所有的Activity的Context都可以替换为getApplicationContext(),getApplicationContext()在startActivity时要新建task,而且在任何时候都不能创建dialog
3、属性无限循环动画持有了Activity里的View,View持有Activity对象,导致Activity无法释放
属性动画中的无限循环动画,在activity的onDestroy中没有停止,导致动画持有了activity的view,view又持有了activity
解决方法:在activity的onDestroy中停止动画
4、 handler导致的内存泄漏(非静态内部类持有外部类的引用导致的内存泄漏)
当handler内部类在不停的处理消息,或者handler内部类在消息发送很长一段时间才处理,会导致内存泄漏。
由于handler是非静态内部类他是一定会持有外部类的引用的,它又在不停的处理消息(或者当activity不可见是它仍在处理消息),所以它一直持有activity对象,导致Activity无法释放
在 Java 语言中,非静态内部类、匿名内部类将持有一个对外部类的隐式引用,而静态内部类则不会持有一个对外部类的隐式引用。
解决方法:
方法一:所以要将handler内部类改为静态内部类;如果需要传入外部类的对象,那么hanler初始化时传入外部类的对象要是弱引用;将所有引用的外部类成员使用WeakReference对象。
方法二:在activity的onDestroy的时候手动清除Message
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null); // 需要在Activity生命周期结束时清除掉CallbacksAndMessages
}
5、小结
禁止任何生命周期与activity生命周期不一致的结构持有activity,结构包括(静态变量、单例模式、动画、生命周期不一致的非静态内部类、匿名类)。有人说了那静态内部类不也和activity生命周期不一致吗,因为是静态不要紧啊只要不持有activity就没事啊,而静态内部类则不会持有一个对外部类的隐式引用。所以只要不持有就没事。
6、其他解决内存泄漏优化内存的方法
(1)java中的基本方法
*使用字符串与包装类时,尽量用直接量创建
*使用StringBuilder和StringBuffer进行字符串连接(而不用String,因为会造成多个对象)
*尽早释放无用的对象引用(及时赋为null)
*尽量少用静态变量
*避免在循环中创建java对象
*缓存经常使用的对象(使用hashmap缓存)
*考虑弱引用、软引用
(2)android中的方法
* 布局尽量减少层级
*布局尽量减少颜色重绘
*默认图片以加载的形式加载,不放在布局background中
*缩小图片大小,能用.9图的用.9图
二、资源泄漏(RESOURCE_LEAK)
及时对资源进行关闭,对于Try catch语句,需要在Finally分支下保证关闭。
public static String getFileMD5(File file) {
if (!file.isFile()) {
return null;
}
MessageDigest digest = null;
FileInputStream in = null;
byte buffer[] = new byte[1024];
int len;
try {
digest = MessageDigest.getInstance("MD5");
in = new FileInputStream(file);
while ((len = in.read(buffer, 0, 1024)) != -1) {
digest.update(buffer, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
return null;
}finally {
CommonUtils.closeQuietly(in); //及时关闭
}
return bytesToHexString(digest.digest());
}
/**
* 静默关闭申请资源,防止产生 RESOURCE_LEAK
* @param closeable
*/
public static void closeQuietly(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (Exception ex) {
// TODO: 2016/1/15 Log or ignore
}
}
}
三、空指针(
NULL_DEREFERENCE
)
一般未对引用判空鉴定。判空即可