java - una - programa para crear aplicaciones android
¿Cómo descubro el uso de memoria de mi aplicación en Android? (8)
1) Supongo que no, al menos no de Java.
2)
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
MemoryInfo mi = new MemoryInfo();
activityManager.getMemoryInfo(mi);
Log.i("memory free", "" + mi.availMem);
¿Cómo puedo encontrar la memoria utilizada en mi aplicación de Android, mediante programación?
Espero que haya una manera de hacerlo. Además, ¿cómo consigo la memoria libre del teléfono también?
Android Studio 0.8.10+ ha introducido una herramienta increíblemente útil llamada Memory Monitor .
Lo que es bueno para:
- Mostrar la memoria disponible y utilizada en un gráfico y los eventos de recolección de basura a lo largo del tiempo.
- Probar rápidamente si la lentitud de la aplicación podría estar relacionada con eventos de recolección excesiva de basura.
- Probar rápidamente si los bloqueos de aplicaciones pueden estar relacionados con quedarse sin memoria.
Figura 1. Forzar un evento GC (recolección de basura) en el monitor de memoria de Android
Puede tener mucha información buena sobre el consumo de RAM en tiempo real de su aplicación al usarla.
Descubrimos que todas las formas estándar de obtener la memoria total del proceso actual tienen algunos problemas.
-
Runtime.getRuntime().totalMemory()
: devuelve solo la memoria JVM -
ActivityManager.getMemoryInfo()
,Process.getFreeMemory()
y cualquier otra cosa basada en/proc/meminfo
: devuelve información de memoria sobre todos los procesos combinados (por ejemplo, android_util_Process.cpp ) -
Debug.getNativeHeapAllocatedSize()
: utilizamallinfo()
que devuelve información sobre las asignaciones de memoria realizadas pormalloc()
y solo funciones relacionadas (consulte android_os_Debug.cpp ) -
Debug.getMemoryInfo()
- hace el trabajo pero es demasiado lento. Se tarda unos 200 ms en Nexus 6 para una sola llamada. La sobrecarga de rendimiento hace que esta función sea inútil para nosotros, ya que la llamamos regularmente y cada llamada es bastante notable (vea android_os_Debug.cpp ) -
ActivityManager.getProcessMemoryInfo(int[])
: llama aDebug.getMemoryInfo()
internamente (consulte ActivityManagerService.java )
Finalmente, terminamos usando el siguiente código:
const long pageSize = 4 * 1024; //`sysconf(_SC_PAGESIZE)`
string stats = File.ReadAllText("/proc/self/statm");
var statsArr = stats.Split(new [] {'' '', ''/t'', ''/n''}, 3);
if( statsArr.Length < 2 )
throw new Exception("Parsing error of /proc/self/statm: " + stats);
return long.Parse(statsArr[1]) * pageSize;
Devuelve la métrica VmRSS . Puedes encontrar más detalles al respecto aquí: one , two y three .
PD : noté que el tema aún carece de un fragmento de código real y simple de cómo estimar el uso de memoria privada del proceso si el rendimiento no es un requisito crítico:
Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
Debug.getMemoryInfo(memInfo);
long res = memInfo.getTotalPrivateDirty();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
res += memInfo.getTotalPrivateClean();
return res * 1024L;
Este es un trabajo en progreso, pero esto es lo que no entiendo:
ActivityManager activityManager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);
Log.i(TAG, " memoryInfo.availMem " + memoryInfo.availMem + "/n" );
Log.i(TAG, " memoryInfo.lowMemory " + memoryInfo.lowMemory + "/n" );
Log.i(TAG, " memoryInfo.threshold " + memoryInfo.threshold + "/n" );
List<RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();
Map<Integer, String> pidMap = new TreeMap<Integer, String>();
for (RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses)
{
pidMap.put(runningAppProcessInfo.pid, runningAppProcessInfo.processName);
}
Collection<Integer> keys = pidMap.keySet();
for(int key : keys)
{
int pids[] = new int[1];
pids[0] = key;
android.os.Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(pids);
for(android.os.Debug.MemoryInfo pidMemoryInfo: memoryInfoArray)
{
Log.i(TAG, String.format("** MEMINFO in pid %d [%s] **/n",pids[0],pidMap.get(pids[0])));
Log.i(TAG, " pidMemoryInfo.getTotalPrivateDirty(): " + pidMemoryInfo.getTotalPrivateDirty() + "/n");
Log.i(TAG, " pidMemoryInfo.getTotalPss(): " + pidMemoryInfo.getTotalPss() + "/n");
Log.i(TAG, " pidMemoryInfo.getTotalSharedDirty(): " + pidMemoryInfo.getTotalSharedDirty() + "/n");
}
}
¿Por qué no se asigna el PID al resultado en activityManager.getProcessMemoryInfo ()? Es evidente que desea que los datos resultantes sean significativos, así que ¿por qué Google ha hecho que sea tan difícil correlacionar los resultados? El sistema actual ni siquiera funciona bien si quiero procesar todo el uso de la memoria, ya que el resultado devuelto es una matriz de objetos android.os.Debug.MemoryInfo, pero ninguno de esos objetos realmente le dice a qué pids están asociados. Si simplemente pasa una serie de todos los pids, no tendrá forma de entender los resultados. Como entiendo su uso, no tiene sentido pasar más de un pid a la vez, y si ese es el caso, ¿por qué hacerlo para que activityManager.getProcessMemoryInfo () solo tome una matriz int?
Hackbod''s es una de las mejores respuestas en . Arroja luz sobre un tema muy oscuro. Me ayudó mucho.
Otro recurso realmente útil es este video de visita obligada: Google I / O 2011: administración de memoria para aplicaciones de Android
ACTUALIZAR:
Process Stats, un servicio para descubrir cómo su aplicación gestiona la memoria explicada en la publicación del blog Process Stats: Entendiendo cómo su aplicación utiliza la memoria RAM por Dianne Hackborn:
Hay una gran cantidad de respuestas arriba que definitivamente te ayudarán, pero (después de 2 días de dinero y de investigación sobre herramientas de memoria adb) creo que también puedo ayudar con mi opinión .
Como dice Hackbod: Por lo tanto, si tomara toda la RAM física asignada a cada proceso y sumara todos los procesos, probablemente terminaría con un número mucho mayor que la RAM total real. así que no hay forma de obtener la cantidad exacta de memoria por proceso.
Pero puedes acercarte a él por alguna lógica ... y te diré cómo ...
Hay algunas API como
android.os.Debug.MemoryInfo
yActivityManager.getMemoryInfo()
mencionadas anteriormente, que quizás ya hayas leído y utilizado, pero hablaré de otra manera
En primer lugar, debe ser un usuario root para que funcione. Ingrese a la consola con privilegios de raíz ejecutando su
en proceso y obtenga su output and input stream
. Luego pase la id/n
(ingrese) en ouputstream y escríbala para procesar la salida. Si obtendré una corriente de entrada que contenga uid=0
, usted es el usuario root.
Ahora aquí está la lógica que usará en el proceso anterior
Cuando obtiene una secuencia de proceso o una secuencia de proceso , ordene (procrank, dumpsys meminfo, etc.) con /n
lugar de id y obtenga su inputstream
y lea, almacene la secuencia en bytes [], char [] etc. use datos en bruto . .y ya terminaste !!!!!
permiso:
<uses-permission android:name="android.permission.FACTORY_TEST"/>
Comprueba si eres usuario root:
// su command to get root access
Process process = Runtime.getRuntime().exec("su");
DataOutputStream dataOutputStream =
new DataOutputStream(process.getOutputStream());
DataInputStream dataInputStream =
new DataInputStream(process.getInputStream());
if (dataInputStream != null && dataOutputStream != null) {
// write id to console with enter
dataOutputStream.writeBytes("id/n");
dataOutputStream.flush();
String Uid = dataInputStream.readLine();
// read output and check if uid is there
if (Uid.contains("uid=0")) {
// you are root user
}
}
Ejecuta tu orden con su
Process process = Runtime.getRuntime().exec("su");
DataOutputStream dataOutputStream =
new DataOutputStream(process.getOutputStream());
if (dataOutputStream != null) {
// adb command
dataOutputStream.writeBytes("procrank/n");
dataOutputStream.flush();
BufferedInputStream bufferedInputStream =
new BufferedInputStream(process.getInputStream());
// this is important as it takes times to return to next line so wait
// else you with get empty bytes in buffered stream
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// read buffered stream into byte,char etc.
byte[] bff = new byte[bufferedInputStream.available()];
bufferedInputStream.read(bff);
bufferedInputStream.close();
}
}
Obtiene datos sin procesar en una sola cadena desde la consola en lugar de, en algún caso, desde cualquier API, que es complejo de almacenar ya que necesitará separarlos manualmente .
Esto es solo un intento, por favor sugiéreme si me perdí algo
Sí, puede obtener información de la memoria mediante programación y decidir si realizar un trabajo de memoria intensiva.
Obtenga VM Hize Size llamando a:
Runtime.getRuntime().totalMemory();
Obtenga memoria virtual asignada llamando a:
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
Obtenga el límite de tamaño de pila de VM llamando a:
Runtime.getRuntime().maxMemory()
Obtenga memoria asignada nativa llamando a:
Debug.getNativeHeapAllocatedSize();
Hice una aplicación para descubrir el comportamiento de OutOfMemoryError y monitorear el uso de la memoria.
https://play.google.com/store/apps/details?id=net.coocood.oomresearch
Puede obtener el código fuente en https://github.com/coocood/oom-research
Tenga en cuenta que el uso de memoria en sistemas operativos modernos como Linux es un área extremadamente complicada y difícil de entender. De hecho, las posibilidades de que realmente interpretes correctamente los números que obtienes son extremadamente bajas. (Casi cada vez que miro los números de uso de la memoria con otros ingenieros, siempre hay una larga discusión sobre lo que realmente significa que solo resulta en una conclusión vaga).
Nota: ahora tenemos una documentación mucho más extensa sobre la gestión de la memoria de su aplicación que cubre gran parte del material aquí y está más actualizada con el estado de Android.
Lo primero es leer la última parte de este artículo, que contiene un análisis de cómo se gestiona la memoria en Android:
Cambios en la API del servicio a partir de Android 2.0
Ahora ActivityManager.getMemoryInfo()
es nuestra API de más alto nivel para observar el uso general de la memoria. Esto es principalmente para ayudar a una aplicación a medir qué tan cerca está el sistema de no tener más memoria para los procesos en segundo plano, por lo que debe comenzar a eliminar los procesos necesarios como los servicios. Para aplicaciones Java puras, esto debería ser de poca utilidad, ya que el límite de almacenamiento dinámico de Java está en parte para evitar que una aplicación pueda estresar el sistema hasta este punto.
Al ir a un nivel inferior, puede usar la API de depuración para obtener información en bruto del nivel de kernel sobre el uso de la memoria: android.os.Debug.MemoryInfo
Tenga en cuenta que a partir de 2.0 también hay una API, ActivityManager.getProcessMemoryInfo
, para obtener esta información sobre otro proceso: ActivityManager.getProcessMemoryInfo(int[])
Esto devuelve una estructura MemoryInfo de bajo nivel con todos estos datos:
/** The proportional set size for dalvik. */
public int dalvikPss;
/** The private dirty pages used by dalvik. */
public int dalvikPrivateDirty;
/** The shared dirty pages used by dalvik. */
public int dalvikSharedDirty;
/** The proportional set size for the native heap. */
public int nativePss;
/** The private dirty pages used by the native heap. */
public int nativePrivateDirty;
/** The shared dirty pages used by the native heap. */
public int nativeSharedDirty;
/** The proportional set size for everything else. */
public int otherPss;
/** The private dirty pages used by everything else. */
public int otherPrivateDirty;
/** The shared dirty pages used by everything else. */
public int otherSharedDirty;
Pero en cuanto a cuál es la diferencia entre Pss
, PrivateDirty
y SharedDirty
... bueno, ahora comienza la diversión.
Una gran cantidad de memoria en Android (y en los sistemas Linux en general) en realidad se comparte a través de múltiples procesos. Entonces, la cantidad de memoria que utiliza un proceso realmente no está clara. Agregue encima de esa paginación al disco (y mucho menos intercambie lo que no usamos en Android) y es aún menos claro.
Por lo tanto, si tuviera que tomar toda la RAM física asignada a cada proceso, y sumara todos los procesos, probablemente terminaría con un número mucho mayor que la RAM total real.
El número de Pss
es una métrica que el núcleo calcula que toma en cuenta el uso compartido de memoria: básicamente, cada página de RAM en un proceso se escala en una proporción del número de otros procesos que también usan esa página. De esta manera puede (en teoría) sumar los pss en todos los procesos para ver la RAM total que están utilizando y comparar los pss entre procesos para tener una idea aproximada de su peso relativo.
La otra métrica interesante aquí es PrivateDirty
, que es básicamente la cantidad de RAM dentro del proceso que no se puede paginar en el disco (no está respaldada por los mismos datos en el disco) y no se comparte con ningún otro proceso. Otra forma de ver esto es la memoria RAM que estará disponible para el sistema cuando el proceso desaparezca (y probablemente se subsume rápidamente en cachés y otros usos del mismo).
Eso es más o menos las API del SDK para esto. Sin embargo, hay más que puedes hacer como desarrollador con tu dispositivo.
Al usar adb
, hay mucha información que puede obtener sobre el uso de la memoria de un sistema en ejecución. Uno común es el comando adb shell dumpsys meminfo
que adb shell dumpsys meminfo
un montón de información sobre el uso de la memoria de cada proceso de Java, que contiene la información anterior, así como una variedad de otras cosas. También puede agregar el nombre o el pid de un solo proceso para ver, por ejemplo, el adb shell dumpsys meminfo system
dame el proceso del sistema:
** MEMINFO in pid 890 [system] ** native dalvik other total size: 10940 7047 N/A 17987 allocated: 8943 5516 N/A 14459 free: 336 1531 N/A 1867 (Pss): 4585 9282 11916 25783 (shared dirty): 2184 3596 916 6696 (priv dirty): 4504 5956 7456 17916 Objects Views: 149 ViewRoots: 4 AppContexts: 13 Activities: 0 Assets: 4 AssetManagers: 4 Local Binders: 141 Proxy Binders: 158 Death Recipients: 49 OpenSSL Sockets: 0 SQL heap: 205 dbFiles: 0 numPagers: 0 inactivePageKB: 0 activePageKB: 0
La sección superior es la principal, donde size
es el tamaño total en el espacio de direcciones de un montón particular, allocated
es el kb de asignaciones reales que el montón cree que tiene, free
es el kb restante que el montón tiene para asignaciones adicionales, y pss
y priv dirty
son los mismos que se analizaron antes de las páginas asociadas con cada uno de los montones.
Si solo desea ver el uso de la memoria en todos los procesos, puede usar el comando adb shell procrank
. La salida de esto en el mismo sistema se ve así:
PID Vss Rss Pss Uss cmdline 890 84456K 48668K 25850K 21284K system_server 1231 50748K 39088K 17587K 13792K com.android.launcher2 947 34488K 28528K 10834K 9308K com.android.wallpaper 987 26964K 26956K 8751K 7308K com.google.process.gapps 954 24300K 24296K 6249K 4824K com.android.phone 948 23020K 23016K 5864K 4748K com.android.inputmethod.latin 888 25728K 25724K 5774K 3668K zygote 977 24100K 24096K 5667K 4340K android.process.acore ... 59 336K 332K 99K 92K /system/bin/installd 60 396K 392K 93K 84K /system/bin/keystore 51 280K 276K 74K 68K /system/bin/servicemanager 54 256K 252K 69K 64K /system/bin/debuggerd
Aquí, las columnas Vss
y Rss
son básicamente ruido (son el espacio de direcciones directo y el uso de RAM de un proceso, donde si sumas el uso de RAM en todos los procesos obtienes un número ridículamente grande).
Pss
es como hemos visto antes, y Uss
es Priv Dirty
.
Una cosa interesante a tener en cuenta aquí: Pss
y Uss
son ligeramente (o más que ligeramente) diferentes a lo que vimos en meminfo
. ¿Porqué es eso? Well procrank utiliza un mecanismo de kernel diferente para recopilar sus datos que meminfo
, y dan resultados ligeramente diferentes. ¿Porqué es eso? Sinceramente no tengo ni idea. Creo que procrank
puede ser el más exacto ... pero en realidad, simplemente deje el punto: "tome cualquier información de memoria que obtenga con un grano de sal; a menudo un grano muy grande".
Finalmente, está el comando adb shell cat /proc/meminfo
que proporciona un resumen del uso general de memoria del sistema. Aquí hay una gran cantidad de datos, solo los primeros números que vale la pena analizar (y los restantes son entendidos por pocas personas, y mis preguntas sobre esas pocas personas sobre ellos a menudo dan como resultado explicaciones conflictivas):
MemTotal: 395144 kB MemFree: 184936 kB Buffers: 880 kB Cached: 84104 kB SwapCached: 0 kB
MemTotal
es la cantidad total de memoria disponible para el kernel y el espacio de usuario (a menudo menos que la RAM física real del dispositivo, ya que parte de esa RAM es necesaria para la radio, los búferes DMA, etc.).
MemFree
es la cantidad de RAM que no se utiliza en absoluto. El número que ves aquí es muy alto; Por lo general, en un sistema Android, esto sería solo unos pocos MB, ya que intentamos usar la memoria disponible para mantener los procesos en ejecución.
Cached
es la memoria RAM que se utiliza para las memorias caché del sistema de archivos y otras cosas similares. Los sistemas típicos necesitarán tener aproximadamente 20 MB para que esto evite estados de paginación incorrectos; el Android out of memory killer está sintonizado para un sistema en particular para asegurarse de que los procesos en segundo plano se eliminen antes de que la memoria RAM almacenada en caché se consuma demasiado para dar lugar a dicha paginación.