2011-05-25 97 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; 
    } 
} 
相关问题