more - ¿Hay alguna forma de que un proceso de Android produzca un volcado de pila en un OutOfMemoryError?
android memory management (3)
La JVM de Sun admite una -XX:+HeapDumpOnOutOfMemoryError
para volcar el montón cuando un proceso java se queda sin montón.
¿Hay una opción similar en Android que haga un montón de volcado de la aplicación de Android en una excepción OutOfMemoryException? Puede ser difícil intentar cronometrarlo correctamente cuando se usa DDMS manualmente.
Aquí hay una versión mejorada. Además de la implementación original, esta implementación también admite:
- Recuperación de errores de memoria en todos los subprocesos (no solo en el subproceso principal)
- Identificación de errores de memoria insuficiente incluso cuando está oculto dentro de un error diferente. En algunos casos, el error de memoria insuficiente se encapsula dentro de un error de tiempo de ejecución.
- También se invoca el controlador de excepciones no capturado predeterminado original.
- Solo funciona en construcciones DEBUG.
Uso: llame al método de initialize
estática en su clase de aplicación en el método 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;
}
}
No tengo idea de si esto funciona, pero puede intentar agregar un controlador de excepciones de nivel superior y solicitar un volcado de pila si es un OutOfMemoryError
.
Para ampliar la respuesta de CommonsWare:
No tengo idea de si esto funciona, pero puede intentar agregar un controlador de excepciones de nivel superior y solicitar un volcado de pila si es un
OutOfMemoryError
.
Seguí su sugerencia con éxito en mi propia aplicación de Android con el siguiente código:
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());
}
}
Después de crear el volcado, debe copiarlo de su teléfono a su PC: haga clic en "Activar almacenamiento USB" en el teléfono, busque el archivo y cópielo en su disco duro.
Luego, si desea utilizar el analizador de memoria Eclipse (MAT) para analizar el archivo, deberá hprof-conv.exe dump.hprof dump-conv.hprof
el archivo: hprof-conv.exe dump.hprof dump-conv.hprof
(hprof-conv se encuentra en android-sdk/tools
)
Finalmente, abra el archivo dump-conv.hprof
con MAT