2011-05-25 96 views

回答

25

要在CommonsWare的回答擴大:

我不知道這是否正常工作,但你可以嘗試adding a top-level exception handler,並在那裏asking for a heap dump如果它是一個OutOfMemoryError

我跟着他的建議成功地在自己的Android應用程序用下面的代碼:

public class MyActivity extends Activity { 
    public static class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { 
     @Override 
     public void uncaughtException(Thread thread, Throwable ex) { 
      Log.e("UncaughtException", "Got an uncaught exception: "+ex.toString()); 
      if(ex.getClass().equals(OutOfMemoryError.class)) 
      { 
       try { 
        android.os.Debug.dumpHprofData("/sdcard/dump.hprof"); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
      ex.printStackTrace(); 
     } 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     Thread.currentThread().setUncaughtExceptionHandler(new MyUncaughtExceptionHandler()); 
    } 
} 

創建轉儲後,您需要將其從手機複製到PC:點擊「打開USB存儲器「,找到該文件並將其複製到您的硬盤驅動器。

然後,如果你想使用Eclipse的內存分析器(MAT)來分析文件,你需要隱蔽的文件:hprof-conv.exe dump.hprof dump-conv.hprof(HPROF-CONV位於android-sdk/tools下)

最後,打開dump-conv.hprof文件與MAT

+0

我注意到,這經常起作用,但有時不會導致轉儲。不知道爲什麼。 – emmby 2013-02-01 00:11:01

+0

我也做了同樣的事情,有時轉儲文件已損壞(或者至少hprof-conv似乎認爲是這樣)。我只會在轉儲之前添加一個建議來執行System.gc()。 – snowdragon 2013-08-08 20:13:18

+1

可能是在寫入文件之前終止了應用程序,或者在完成之前終止了應用程序(更糟糕)。 – 2014-03-21 03:47:23

8

這是一個改進版本。在原有執行此之上實現還支持:

  • 捉出的所有線程的內存錯誤(不只是在主線程)
  • 識別出,即使它是隱藏的不同的錯誤裏面的內存錯誤。在某些情況下,Out of Memory錯誤被封裝在運行時錯誤中。
  • 也調用原始的默認未捕獲異常處理程序。
  • 只適用於DEBUG版本。

用法:在onCreate方法的Application類中調用靜態initialize方法。

package test; 
import java.io.File; 
import java.io.IOException; 
import java.lang.Thread.UncaughtExceptionHandler; 

import android.os.Environment; 
import android.util.Log; 

import com.example.test1.BuildConfig; 

public class OutOfMemoryDumper implements Thread.UncaughtExceptionHandler { 

    private static final String TAG = "OutOfMemoryDumper"; 
    private static final String FILE_PREFIX = "OOM-"; 
    private static final OutOfMemoryDumper instance = new OutOfMemoryDumper(); 

    private UncaughtExceptionHandler oldHandler; 

    /** 
    * Call this method to initialize the OutOfMemoryDumper when your 
    * application is first launched. 
    */ 
    public static void initialize() { 

     // Only works in DEBUG builds 
     if (BuildConfig.DEBUG) { 
      instance.setup(); 
     } 
    } 

    /** 
    * Keep the constructor private to ensure we only have one instance 
    */ 
    private OutOfMemoryDumper() { 
    } 

    private void setup() { 

     // Checking if the dumper isn't already the default handler 
     if (!(Thread.getDefaultUncaughtExceptionHandler() instanceof OutOfMemoryDumper)) { 

      // Keep the old default handler as we are going to use it later 
      oldHandler = Thread.getDefaultUncaughtExceptionHandler(); 

      // Redirect uncaught exceptions to this class 
      Thread.setDefaultUncaughtExceptionHandler(this); 
     } 
     Log.v(TAG, "OutOfMemoryDumper is ready"); 
    } 

    @Override 
    public void uncaughtException(Thread thread, Throwable ex) { 

     Log.e(TAG, "Uncaught exception: " + ex); 
     Log.e(TAG, "Caused by: " + ex.getCause()); 

     // Checking if the exception or the original cause for the exception is 
     // an out of memory error 
     if (ex.getClass().equals(OutOfMemoryError.class) 
       || (ex.getCause() != null && ex.getCause().getClass() 
         .equals(OutOfMemoryError.class))) { 

      // Checking if the external storage is mounted and available 
      if (isExternalStorageWritable()) { 
       try { 

        // Building the path to the new file 
        File f = Environment 
          .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); 

        long time = System.currentTimeMillis(); 

        String dumpPath = f.getAbsolutePath() + "/" + FILE_PREFIX 
          + time + ".hprof"; 

        Log.i(TAG, "Dumping hprof data to: " + dumpPath); 

        android.os.Debug.dumpHprofData(dumpPath); 

       } catch (IOException ioException) { 
        Log.e(TAG,"Failed to dump hprof data. " + ioException.toString()); 
        ioException.printStackTrace(); 
       } 
      } 
     } 

     // Invoking the original default exception handler (if exists) 
     if (oldHandler != null) { 
      Log.v(TAG, "Invoking the original uncaught exception handler"); 
      oldHandler.uncaughtException(thread, ex); 
     } 
    } 

    /** 
    * Checks if external storage is available for read and write 
    * 
    * @return true if the external storage is available 
    */ 
    private boolean isExternalStorageWritable() { 
     String state = Environment.getExternalStorageState(); 
     if (Environment.MEDIA_MOUNTED.equals(state)) { 
      return true; 
     } 
     Log.w(TAG,"The external storage isn't available. hprof data won't be dumped! (state=" + state + ")"); 
     return false; 
    } 
} 
相關問題