Есть ли способ заставить процесс Android производить дамп кучи на OutOfMemoryError? - PullRequest
17 голосов
/ 26 мая 2011

Sun JVM поддерживает опцию -XX:+HeapDumpOnOutOfMemoryError для выгрузки кучи всякий раз, когда у процесса Java заканчивается куча.

Существует ли аналогичная опция на Android, которая будет создавать кучу дампов приложений Android для исключения OutOfMemoryException? Может быть трудно попытаться правильно рассчитать время при использовании DDMS вручную.

Ответы [ 3 ]

26 голосов
/ 04 августа 2011

Чтобы расширить ответ CommonsWare:

Я понятия не имею, работает ли это, но вы можете попробовать добавить обработчик исключений верхнего уровня , и там запрашивая дамп кучи , если это 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());
    }
}

Последамп создан, вам нужно скопировать его с телефона на компьютер: нажмите «Включить USB-накопитель» на телефоне, найдите файл и скопируйте его на жесткий диск.

Затем, если хотите,чтобы использовать Eclipse Memory Analyzer (MAT) для анализа файла, вам нужно будет преобразовать файл: hprof-conv.exe dump.hprof dump-conv.hprof (hprof-conv находится в android-sdk/tools)

Наконец, откройте файл dump-conv.hprofс MAT

9 голосов
/ 30 сентября 2014

Вот улучшенная версия. Помимо первоначальной реализации, эта реализация также поддерживает:

  • Ошибки Catching Out of Memory во всех потоках (не только в основном потоке)
  • Идентификация ошибок нехватки памяти, даже если она скрыта внутри другой ошибки. В некоторых случаях ошибка «Недостаточно памяти» инкапсулируется внутри ошибки времени выполнения.
  • Вызов также исходного обработчика необработанных исключений по умолчанию.
  • Работает только в сборках DEBUG.

Использование: вызовите статический метод initialize в вашем классе Application в методе onCreate .

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;
    }
}
9 голосов
/ 26 мая 2011

Понятия не имею, работает ли это, но вы можете попробовать добавить обработчик исключений верхнего уровня , и там запросить дамп кучи , если это OutOfMemoryError.

...