有没有办法让Android进程在OutOfMemoryError上产生堆转储?

问题描述

| 当Java进程用完堆时,sun JVM支持ѭ0选项来转储堆。 Android上是否有类似的选项,可以在OutOfMemoryException上生成android应用程序转储堆?手动使用DDMS时,可能很难尝试正确计时。     

解决方法

扩展CommonsWare的答案:   我不知道这是否可行,但是您可以尝试添加顶级异常处理程序,并在其中请求堆转储(如果它是1)。 我在自己的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 Memory Analyzer(MAT)分析文件,则需要隐藏文件:
hprof-conv.exe dump.hprof dump-conv.hprof
(hprof-conv位于
android-sdk/tools
下) 最后,用MAT打开
dump-conv.hprof
文件     ,我不知道这是否可行,但是您可以尝试添加顶级异常处理程序,并在其中请求堆转储(如果它是1)。     ,这是一个改进的版本。除了原始实现之外,该实现还支持: 在所有线程上(不仅在主线程上)捕获内存不足错误 识别出内存不足错误,即使它隐藏在另一个错误中。在某些情况下,内存不足错误会封装在运行时错误中。 也调用原始的默认未捕获异常处理程序。 仅适用于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;
    }
}