Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android 內存洩露小計

android 內存洩露小計

編輯:關於Android編程

1 今天在調試android 程序時候,發現即使程序退出了,發現還占用內存大概有15M.用MAT查看,經過多次GC操作,發現依舊是15.直覺告訴我,應該發生內存洩露了。然後利用MAT,查看Memory Leak。結果讓我很吃驚,發現是InputMethodManager。這個對象一直引用著Context。也就是Activity,導致它無法釋放內存。後來google 一下發現,

以下貼出解決辦法,希望給遇到類似情況的人,提供幫助:

 

@Override
protected void onDestroy()
{
    super.onDestroy();
    //fix for memory leak: http://code.google.com/p/android/issues/detail?id=34731
    fixInputMethodManager();
}

private void fixInputMethodManager()
{
    final Object imm = getSystemService(Context.INPUT_METHOD_SERVICE);

    final Reflector.TypedObject windowToken
        = new Reflector.TypedObject(getWindow().getDecorView().getWindowToken(), IBinder.class);

    Reflector.invokeMethodExceptionSafe(imm, "windowDismissed", windowToken);

    final Reflector.TypedObject view
        = new Reflector.TypedObject(null, View.class);

    Reflector.invokeMethodExceptionSafe(imm, "startGettingWindowFocus", view);
}
就是通過反射調用windowDismissed和startGettingWindowFocus。本來以為這個問題就這樣搞定了,誰知道又出現了一個更加奇葩的情況。我發現竟然還有一個更奇葩的對象:com.lflytek.speech.a.a.a。腦子懵了一下,這是啥東東?通過百度這個查詢,發現這是科大訊飛的語音識別sdk。對,腦子確實懵了。但是不對啊。這個對象怎麼生命周期那麼長。不對,肯定哪裡搞錯了。後來通過源代碼閱讀:

 

 

public RecognizerDialog(Context paramContext, String paramString)
  {
    super(paramContext);
    this.a = new a(paramContext, paramString);
  }

  public void setListener(RecognizerDialogListener paramRecognizerDialogListener)
  {
    ((a)this.a).a(paramRecognizerDialogListener);
  }
這是sdk唯一能得到我應用程序的地方,其他的都是設置一些信息。難道問題就出在這個地方?對,你答對了!

 

表面上看起來這沒有任何問題,你看我們很多應用程序sdk不都是這麼弄的嘛,這很正常啊。沒辦法,雖然代碼混淆過了,可我為了搞清楚事情真相只能硬著頭皮去讀。通過代碼不斷的追蹤,終於發現秘密了。


在com.iflytek.speech.a.a中有一個很奇葩的私有的類成員。

private static a e=null

 

  public static com.iflytek.speech.b b(Context paramContext, String paramString)
  {
    if (e == null)
      e = new a(paramContext, paramString);
    return e;
  }

你這不是坑人嗎?干嘛非要用靜態呢,這樣就造成了e的生命周期長與Activity,也就造成了內存洩露。(後來在看混淆過的科大訊飛sdk代碼時,發現原來它在采集設備的位置信息和應用程序的包名和相關簽名信息,當然這也無可厚非,人家畢竟要驗證應用程序的包名和簽名)。這可咋辦,這個靜態又是私有的。對了,想到反射了。

 

以下貼出反射的代碼。

 

@Override
	public void finish() {
		com.iflytek.a.a.a=null;
		try {
			Class clazz=Class.forName("com.iflytek.speech.a.a");
			Field field=clazz.getDeclaredField("e");
			if (field.isAccessible()==false) {
				field.setAccessible(true);
			}
			field.set(null, null);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		super.finish();		
	}

然後再調試,發現這個問題總算解決了。

 

看來以後用第三方sdk的時候,得注意點了,不能隨便用啊。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved