dumpsys meminfo explicación detallada

Código fuente basado en: Android R

0. Prefacio

De hecho, dumpsys meminfo se analizó en el artículo sobre cómo ver el uso de la memoria en Android hace mucho tiempo  , pero recientemente, cuando conté los datos de la memoria, descubrí que no era correcto, así que volví a analizar el código fuente. al  ver el uso de la memoria en Android, Esta publicación de blog analizará el proceso del servicio meminfo y el volcado bajo AMS en detalle en combinación con el código.

1. El punto de partida de meminfo dumpsys

Las estadísticas de meminfo en AMS se vuelcan mediante el comando dumpsys, que se almacena en el archivo bin en /system/bin/. El directorio del código fuente se encuentra en frameworks/native/cmds/dumpsys/ Para obtener más información, consulte  el artículo de dumpsys en android .

2. servicios meminfo -- MemBinder

Todos los servicios que se pueden volcar se agregan en ServiceManager. Por ejemplo, meminfo se agrega en la función setSystemProcess de frameworks/base/services/java/com/android/server/am/ActivityManagerService.java:

frameworks/base/services/core/java/com/android/server/am/AMS.java


public void setSystemProcess() {
        try {
            ...

            ServiceManager.addService("meminfo", new MemBinder(this), /* allowIsolated= */ false,
                    DUMP_FLAG_PRIORITY_HIGH);

            ...
}

 Aviso:

 A través  del paso 7 del artículo dumpsys en android , sabemos que si un servicio (por ejemplo, meminfo) necesita realizar una operación de volcado a través del comando dumpsys, se debe especificar el indicador de volcado. Aquí meminfo especifica el indicador de volcado como DUMP_FLAG_PRIORITY_HIGH cuando addService  .

Echa un vistazo a continuación:

frameworks/base/services/core/java/com/android/server/am/AMS.java

   static class MemBinder extends Binder {
        ActivityManagerService mActivityManagerService;
        private final PriorityDump.PriorityDumper mPriorityDumper =
                new PriorityDump.PriorityDumper() {
            @Override
            public void dumpHigh(FileDescriptor fd, PrintWriter pw, String[] args,
                    boolean asProto) {
                dump(fd, pw, new String[] {"-a"}, asProto);
            }

            @Override
            public void dump(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
                mActivityManagerService.dumpApplicationMemoryUsage(
                        fd, pw, "  ", args, false, null, asProto);
            }
        };

        MemBinder(ActivityManagerService activityManagerService) {
            mActivityManagerService = activityManagerService;
        }

        @Override
        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
            try {
                mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);

                if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
                        "meminfo", pw)) return;
                PriorityDump.dump(mPriorityDumper, fd, pw, args);
            } finally {
                mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
            }
        }
    }

Hay dos variables miembro definidas en él:

  • mActivityManagerService: registrar objetos AMS;
  • mPriorityDumper: a través de su interfaz dump(), conéctese a AMS.dumpApplicationMemoryUsage();

La implementación real está en dumpApplicationMemoryUsage() de AMS.

3. dumpsys meminfo-h

Después de ingresar dumpApplicationMemoryUsage(), verá un ciclo while para analizar los parámetros adjuntos a dumpsys meminfo.Aquí, primero mire -h, y use este parámetro para comprender mejor otras opciones de parámetros de dumpsys meminfo.

El código no se publica aquí, solo mire la salida de la terminal:

meminfo dump options: [-a] [-d] [-c] [-s] [--oom] [process]
  -a: include all available information for each process.
  -d: include dalvik details.
  -c: dump in a compact machine-parseable representation.
  -s: dump only summary of application memory usage.
  -S: dump also SwapPss.
  --oom: only show processes organized by oom adj.
  --local: only collect details locally, don't call process.
  --package: interpret process arg as package, dumping all
             processes that have loaded that package.
  --checkin: dump data for a checkin
  --proto: dump data to proto
If [process] is specified it can be the name or
pid of a specific process to dump.
  • -a: Contiene toda la información disponible, más precisamente contiene -d, -s, -S;
  • -d: necesita incluir detalles de dalvik;
  • -c: volcar en una representación comprimida analizable por máquina;
  • -s: solo volca el resumen de la memoria de la aplicación;
  • -S: volcar la información de swap pss;
  • --oom: solo descarga la información de ajuste OOM de RSS/PSS;
  • --local: solo recopila información localmente y solo tiene efecto cuando se especifica mediante -a o -s;
  • --paquete: volca todos los procesos que cargan el paquete especificado;
  • --checkin: descarga los datos para registrarse;
  • --proto: volcado de datos de prototipo;
  • dumpsys meminfo puede ir seguido de [proceso], este proceso puede ser el nombre del proceso o el pid del proceso;

4. recogerProcesos()

Después de analizar los parámetros de la línea de comandos de dumpsys meminfo, se llamará a collectProcesses() para confirmar los paquetes o pids que coincidan con el comando:

frameworks/base/services/core/java/com/android/server/am/ProcessList.java

   ArrayList<ProcessRecord> collectProcessesLocked(int start, boolean allPkgs, String[] args) {
        ArrayList<ProcessRecord> procs;
        if (args != null && args.length > start
                && args[start].charAt(0) != '-') {
            procs = new ArrayList<ProcessRecord>();
            int pid = -1;
            try {
                pid = Integer.parseInt(args[start]);
            } catch (NumberFormatException e) {
            }
            for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
                ProcessRecord proc = mLruProcesses.get(i);
                if (proc.pid > 0 && proc.pid == pid) {
                    procs.add(proc);
                } else if (allPkgs && proc.pkgList != null
                        && proc.pkgList.containsKey(args[start])) {
                    procs.add(proc);
                } else if (proc.processName.equals(args[start])) {
                    procs.add(proc);
                }
            }
            if (procs.size() <= 0) {
                return null;
            }
        } else {
            procs = new ArrayList<ProcessRecord>(mLruProcesses);
        }
        return procs;
    }

El código sigue siendo relativamente claro:

  • Si la línea de comando especifica pid, recopile estos procesos;
  • Si se establece packageName, recopile estos paquetes;
  • Si no se establece, recopile todos los procesos de LRU;

Tenga en cuenta que el proceso recopilado en los dos primeros puntos puede estar vacío, porque los parámetros establecidos pueden ser falsos o no pueden coincidir.

En este momento, la terminal también indica Sin proceso:

shift:/ # dumpsys meminfo 12345
No se encontró ningún proceso para: 12345

5. dumpApplicationMemoryUsage()

La cantidad de código para esta función es demasiado grande, así que analicemos los puntos clave aquí.

5.1 Varias variables thread, pid, omadj, mi

frameworks/base/services/core/java/com/android/server/am/AMS.java

    private final void dumpApplicationMemoryUsage() {

        ...

        for (int i = numProcs - 1; i >= 0; i--) {
            final ProcessRecord r = procs.get(i);
            final IApplicationThread thread;
            final int pid;
            final int oomAdj;
            final boolean hasActivities;
            synchronized (this) {
                thread = r.thread;
                pid = r.pid;
                oomAdj = r.getSetAdjWithServices();
                hasActivities = r.hasActivities();
            }
            if (thread != null) {
                if (mi == null) {
                    mi = new Debug.MemoryInfo();
                }

Al principio, debe prestar atención a varias inicializaciones clave:

  • subproceso: especifique IApplicationThread.Cuando --local no está configurado (la mayoría de ellos no se configurarán), los datos del lado de la aplicación deben leerse a través de este subproceso   y pasarse a AMS a través de la canalización .
  • oomAdj: un importante conjunto de datos en dumpsys meminfo, para LMKD, consulte el artículo sobre el análisis de algoritmos de la puntuación adj en detalle;
  • pid: el pid de la aplicación actual, se mostrará junto con dumpsys meminfo;
  • mi: el núcleo de los datos de la memoria, esta variable se explicará en detalle a continuación, vea la Sección 5.2 para más detalles ;

5.2 Depurar.MemoryInfo()

Directorio fuente: frameworks/base/core/java/android/os/Debug.java

Aquí se proporcionan muchas interfaces nativas:

    public static native long getNativeHeapSize();
    public static native long getNativeHeapAllocatedSize();
    public static native long getNativeHeapFreeSize();
    public static native void getMemoryInfo(MemoryInfo memoryInfo);
    public static native boolean getMemoryInfo(int pid, MemoryInfo memoryInfo);
    public static native long getPss();
    public static native long getPss(int pid, long[] outUssSwapPssRss, long[] outMemtrack);

5.3 Depurar.getMemoryInfo()

Luego, el código en la Sección 5.1 continúa mirando hacia abajo:

                if (opts.dumpDetails || (!brief && !opts.oomOnly)) {
                    reportType = ProcessStats.ADD_PSS_EXTERNAL_SLOW;
                    startTime = SystemClock.currentThreadTimeMillis();
                    if (!Debug.getMemoryInfo(pid, mi)) {
                        continue;
                    }
                    endTime = SystemClock.currentThreadTimeMillis();
                    hasSwapPss = mi.hasSwappedOutPss;
                } else {
                    reportType = ProcessStats.ADD_PSS_EXTERNAL;
                    startTime = SystemClock.currentThreadTimeMillis();
                    long pss = Debug.getPss(pid, tmpLong, null);
                    if (pss == 0) {
                        continue;
                    }
                    mi.dalvikPss = (int) pss;
                    endTime = SystemClock.currentThreadTimeMillis();
                    mi.dalvikPrivateDirty = (int) tmpLong[0];
                    mi.dalvikRss = (int) tmpLong[2];
                }
  • opts.dumpDetails se utiliza principalmente para obtener información detallada de la aplicación. Generalmente, esta variable se establece en verdadero al especificar pid o paquete, o al especificar directamente el parámetro de comando -s;
  • El valor predeterminado de breve es falso, que se pasa desde MemBinder;
  • opts.oomOnly se establece en verdadero solo cuando se especifica --oom;

Cuando no se especifica --oom, el código pasará por el caso if y la información detallada de la memoria del proceso se obtendrá a través de Debug.getMemoryInfo():

frameworks/base/core/jni/android_os_Debug.cpp

static jboolean android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
        jint pid, jobject object)
{
    bool foundSwapPss;
    stats_t stats[_NUM_HEAP];
    memset(&stats, 0, sizeof(stats));

    if (!load_maps(pid, stats, &foundSwapPss)) {
        return JNI_FALSE;
    }

    struct graphics_memory_pss graphics_mem;
    if (read_memtrack_memory(pid, &graphics_mem) == 0) {
        stats[HEAP_GRAPHICS].pss = graphics_mem.graphics;
        ...
    }

    for (int i=_NUM_CORE_HEAP; i<_NUM_EXCLUSIVE_HEAP; i++) {
        stats[HEAP_UNKNOWN].pss += stats[i].pss;
        ...
    }

    for (int i=0; i<_NUM_CORE_HEAP; i++) {
        env->SetIntField(object, stat_fields[i].pss_field, stats[i].pss);
        ...
    }

    env->SetBooleanField(object, hasSwappedOutPss_field, foundSwapPss);

    ...

    for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
        ...
    }

    env->ReleasePrimitiveArrayCritical(otherIntArray, otherArray, 0);
    return JNI_TRUE;
}
  • Obtenga la información de memoria del proceso desde /proc/ pid /smaps a través de load_maps() ;
  • Obtenga información de la memoria gráfica a través de libmemtrack.so mediante read_memtrack_memory();
  • Configure la información de grupo de UNKNOWN, dalvik y heap en Meminfo a través de env->SetIntField()  ;
  • Establezca otra información en MemoryInfo.otherStats[] a través de otherArray;

5.3.1 cargar_mapas()

static bool load_maps(int pid, stats_t* stats, bool* foundSwapPss)
{
    *foundSwapPss = false;
    uint64_t prev_end = 0;
    int prev_heap = HEAP_UNKNOWN;

    std::string smaps_path = base::StringPrintf("/proc/%d/smaps", pid);
    auto vma_scan = [&](const meminfo::Vma& vma) {
        ...
    };

    return meminfo::ForEachVmaFromFile(smaps_path, vma_scan);
}

meminfo::ForEachVmaFromFile() es la interfaz libmeminfo.so, el código se encuentra en /system/memory/libmeminfo/.

Aquí hay un resumen de un diagrama de marco de llamada:

Principalmente lee el nodo de smaps del proceso. Según diferentes atributos, el espacio de direcciones virtuales del proceso se dividirá en varios VMA. Cada VMA forma una lista doblemente enlazada a través de vm_next y vm_prev. La lista enlazada se encuentra en task_struct->mm_struct ->mapa del proceso. Al leer el archivo smaps de un proceso a través de la interfaz proc, el kernel primero encontrará el encabezado de la lista vinculada de vma del proceso, recorrerá cada vma en la lista vinculada, contará el uso de este vma a través de walk_page_vma y finalmente lo mostrará .

Aquí están las estadísticas de uno de los VMA:

  • Rss: Memoria física residente, que es la memoria física que realmente tiene el proceso en la RAM. Rss incluye la memoria ocupada por la biblioteca compartida, por lo que puede resultar engañoso;
  • Pss: memoria física utilizada en proporción, la diferencia entre Pss y Rss es que Pss cuenta el uso de memoria promedio de las bibliotecas compartidas. Si un so ocupa 30kb de memoria, y este so es compartido por 3 procesos, entonces la memoria ocupada por el so en las estadísticas de un determinado proceso Pss es 30/3 kb;
  • Private_Dirty: datos de memoria privada, solo Dirty, lo contrario de Private_Clean. Dirty incluye page_dirty y pte_dirty, page_dirty es la llamada página sucia (el archivo se lee y modifica en la memoria, se marcará como página sucia). Para pte_dirty, cuando el vma se usa como anónimo, se llama a do_anonymous_page cuando leer y escribir este vma activa una falla de página.Si vma_flags contiene VM_WRITE, pasará el indicador pte_mkdirty(entrada);
  • Private_Clean: datos limpios privados, opuestos a Private_Dirty;
  • Shared_Dirty: igual que Private_Dirty, al menos otro proceso hace referencia a la memoria y al menos un proceso la está modificando;
  • Shared_Clean: Igual que Private_Clean, opuesto a Shared_Dirty;
  • Intercambio: la página nativa que se intercambiará se puede llamar SwapRss;
  • SwapPss: Páginas nativas que se intercambian, contadas según el ratio;

En general, en Android, es ZRAM, que aumenta la cantidad de memoria disponible en el sistema al comprimir páginas de memoria y colocarlas en un área de intercambio de memoria asignada dinámicamente. Las páginas comprimidas son todas páginas anónimas.

Pero la siguiente sección de vma es una asignación de archivos, pero también hay un campo de intercambio, porque este archivo se transfiere al espacio de direcciones del proceso a través de mmap. Cuando hay MAP_PRIVATE en la etiqueta, significa que es un mapeo de copia en escritura. Aunque está respaldado por archivos, al escribir datos en estos datos, los datos se copiarán en la página anónima, así que consulte el Anónimo anterior . : También es 0.

5.3.2 Comparación entre enumeración vma y HEAP en smaps

[montón]

[ano:libc_malloc]

[ano:escudo:

[anónimo:GWP-ASan

HEAP_NATIVO

[ano:dalvik-*

HEAP_DALVIK_OTHER
*.entonces HEAP_SO
*.frasco HEAP_JAR
*.apk HEAP_APK
*.ttf HEAP_TTF

*.odex (*.dex)

HEAP_DEX

---- HEAP_DEX_APP_DEX

*.vdex (@arranque /arranque /apex)

HEAP_DEX

----HEAP_DEX_BOOT_VDEX

----HEAP_DEX_APP_VDEX

*.avena HEAP_OAT

*.arte

*.arte] (@arranque /arranque /apex)

HEAP_ART

---- HEAP_ART_BOOT

---- HEAP_ART_APLICACIÓN

/dev/ HEAP_UNKNOWN_DEV
/dev/kgsl-3d0 HEAP_GL_DEV
/dev/ashmem/CursorWindow HEAP_CURSOR

/dev/ashmem/jit-zygote-cache

/memfd:jit-caché

/memfd:jit-zygote-cache

HEAP_DALVIK_OTHER
/dev/ashmem HEAP_ASHMEM

Consulte la función load_maps() para obtener información detallada sobre which_heap y sub_heap.

5.3.3 read_memtrack_memory()

A través de esta función, obtenga la memoria asignada del proceso en la GPU.

El siguiente es el diagrama de marco de llamada:

 La imagen de arriba lee la memoria asignada por el proceso en la GPU, y cada fabricante puede tener diferentes estrategias estadísticas, que también es la razón de la capa HAL.


5.4 hilo.dumpMemInfo()

Varias variables importantes se enumeran en la Sección 5.1, una de las cuales es IApplicationThread, que es única para cada proceso.

Por supuesto, este caso es cuando opts.dumpDetails es verdadero, es decir, meminfo para una sola aplicación;

       try {
            TransferPipe tp = new TransferPipe();
            try {
                thread.dumpMemInfo(tp.getWriteFd(),
                        mi, opts.isCheckinRequest, opts.dumpFullDetails,
                        opts.dumpDalvik, opts.dumpSummaryOnly, opts.dumpUnreachable, innerArgs);
                tp.go(fd, opts.dumpUnreachable ? 30000 : 5000);
            } finally {
                tp.kill();
            }

Cree un objeto TransferPipe, que creará un hilo y una tubería. Luego escriba Fd en ActivithThread del proceso de la aplicación y ActivityThread analizará el uso de memoria del proceso de la aplicación. Cuando se llama a la función go (), el hilo creado por TransferPipe se iniciará y esperará la comunicación de la tubería.Si AMS obtiene los datos a través de readFd, notificará al proceso dumpsys para indicar que el volcado se completó.

Veamos dumpMemInfo():

 ---->

frameworks/base/core/java/android/app/ActivityThread.java

        public void dumpMemInfo(ParcelFileDescriptor pfd, Debug.MemoryInfo mem, boolean checkin,
                boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly,
                boolean dumpUnreachable, String[] args) {
            FileOutputStream fout = new FileOutputStream(pfd.getFileDescriptor());
            PrintWriter pw = new FastPrintWriter(fout);
            try {
                dumpMemInfo(pw, mem, checkin, dumpFullInfo, dumpDalvik, dumpSummaryOnly, dumpUnreachable);
            } finally {
                pw.flush();
                IoUtils.closeQuietly(pfd);
            }
        }

El código detallado no se analizará más aquí, pero se resume un diagrama de marco de llamada:

En dumpMeminfo(), totalMemory y freeMemory del proceso de la aplicación dalvik se obtendrán a través de getRuntime(), y dalvikAllocated se calculará para obtener el uso de memoria de la máquina virtual del proceso de la aplicación.

Y use tres interfaces nativas como Debug.getNativeHeapSize() para contar el uso nativo del proceso de la aplicación. Aquí está lo mismo que en la Sección 5.3 anterior, y seguirá ingresando androi_os_Debug.cpp:

frameworks/base/core/jni/android_os_Debug.cpp

static jlong android_os_Debug_getNativeHeapSize(JNIEnv *env, jobject clazz)
{
    struct mallinfo info = mallinfo();
    return (jlong) info.usmblks;
}

static jlong android_os_Debug_getNativeHeapAllocatedSize(JNIEnv *env, jobject clazz)
{
    struct mallinfo info = mallinfo();
    return (jlong) info.uordblks;
}

static jlong android_os_Debug_getNativeHeapFreeSize(JNIEnv *env, jobject clazz)
{
    struct mallinfo info = mallinfo();
    return (jlong) info.fordblks;
}

mallinfo() devuelve estadísticas de asignación de memoria. La función se declara en android/bionic/libc/include/malloc.h, y la función se define en android/bionic/libc/bionic/malloc_common.cpp:

extern "C" struct mallinfo mallinfo() {
  auto dispatch_table = GetDispatchTable();
  if (__predict_false(dispatch_table != nullptr)) {
    return dispatch_table->mallinfo();
  }
  return Malloc(mallinfo)();
}

mallinfo() principalmente devuelve una estructura, que contiene la información de memoria solicitada por malloc() y sus llamadas a funciones relacionadas. La siguiente es la información específica de la estructura mallinfo (ver man para más información):

   struct mallinfo {
       int arena;     /* Non-mmapped space allocated (bytes) */
       int ordblks;   /* Number of free chunks */
       int smblks;    /* Number of free fastbin blocks */
       int hblks;     /* Number of mmapped regions */
       int hblkhd;    /* Space allocated in mmapped regions (bytes) */
       int usmblks;   /* Maximum total allocated space (bytes) */
       int fsmblks;   /* Space in freed fastbin blocks (bytes) */
       int uordblks;  /* Total allocated space (bytes) */
       int fordblks;  /* Total free space (bytes) */
       int keepcost;  /* Top-most, releasable space (bytes) */
   };

Los tres datos que devolvemos aquí:

  • usmblks: la memoria total máxima de alloc (unidad: byte);
  • uordblks: memoria de asignación total (unidad: byte);
  • fordblks: memoria libre total (unidad: byte);

 Estas dos entradas se muestran en la siguiente figura: 

5.5 MemInfoReader

Antes de usar MemInfoReader, debe volver al principio del código y comprender la variable collectNative:

final boolean collectNative = !opts.isCheckinRequest && numProcs > 1 && !opts.packages;

Al volcar el meminfo de varias aplicaciones o de todas las aplicaciones, la variable collectNative se establece en verdadero; si solo se imprime el meminfo de una sola aplicación, el valor es falso, por lo que no se imprimirá al final.

    MemInfoReader memInfo = new MemInfoReader();
    memInfo.readMemInfo();

El código detallado ya no se analiza, aquí hay un resumen de un marco de llamada:

La salida es la siguiente:

6. análisis de datos meminfo

6.1 meminfo para una sola aplicación

shift:/ # dumpsys meminfo com.android.launcher3
Applications Memory Usage (in Kilobytes):
Uptime: 4443605 Realtime: 4443605

** MEMINFO in pid 1834 [com.android.launcher3] **
                   Pss  Private  Private     Swap      Rss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty    Total     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------   ------
  Native Heap    13647    13548        0        0    16152    21672    16064     1962
  Dalvik Heap     5338     5144        0        0     9496     6657     3329     3328
 Dalvik Other     1317     1192        0        0     2376
        Stack      636      636        0        0      644
       Ashmem        2        0        0        0       20
    Other dev      140        0      140        0      392
     .so mmap     7350      232       12        0    57116
    .jar mmap     2359        0       76        0    24984
    .apk mmap    22108        0    15208        0    51748
    .ttf mmap      110        0        0        0      376
    .dex mmap      348        8      336        0      432
    .oat mmap     1384        0        0        0    14560
    .art mmap     2434     1608        4        0    20496
   Other mmap      495       60       24        0     2896
      Unknown      599      588        0        0     1128
        TOTAL    58267    23016    15800        0    58267    28329    19393     5290

 App Summary
                       Pss(KB)                        Rss(KB)
                        ------                         ------
           Java Heap:     6756                          29992
         Native Heap:    13548                          16152
                Code:    15872                         149484
               Stack:      636                            644
            Graphics:        0                              0
       Private Other:     2004
              System:    19451
             Unknown:                                    6544

           TOTAL PSS:    58267            TOTAL RSS:   202816      TOTAL SWAP (KB):        0

 Objects
               Views:       89         ViewRootImpl:        1
         AppContexts:       10           Activities:        1
              Assets:       14        AssetManagers:        0
       Local Binders:       34        Proxy Binders:       43
       Parcel memory:       13         Parcel count:       69
    Death Recipients:        1      OpenSSL Sockets:        0
            WebViews:        0

 SQL
         MEMORY_USED:      682
  PAGECACHE_OVERFLOW:      292          MALLOC_SIZE:      117

 DATABASES
      pgsz     dbsz   Lookaside(b)          cache  Dbname
         4       16             20         1/14/1  /data/user/0/com.android.launcher3/databases/widgetpreviews.db
         4      252             71        99/18/5  /data/user/0/com.android.launcher3/databases/app_icons.db
         4       16             57         6/17/4  /data/user/0/com.android.launcher3/databases/launcher.db

Veamos algunos de los conceptos principales:

           Java Heap:    24312  dalvik heap + .art mmap
         Native Heap:    62256
                Code:    66452    .so mmap + .jar mmap + .apk mmap + .ttf mmap + .dex mmap + .oat mmap
               Stack:       84
            Graphics:     5338    Gfx dev + EGL mtrack + GL mtrack
       Private Other:     9604  TotalPrivateClean + TotalPrivateDirty - java - native - code - stack - graphics
              System:    12900    TotalPss - TotalPrivateClean - TotalPrivateDirty

https://developer.android.com/studio/profile/investigate-ram?hl=zh-cn

  • Montón de Dalvík

RAM utilizada por las asignaciones de Dalvik en la aplicación. Pss Total incluye todas las asignaciones de Zygote (medidas por la cantidad de memoria compartida entre procesos como se describe en la definición de PSS anterior). El número Private Dirty es RAM real asignada solo al montón de su aplicación, que consiste en sus propias asignaciones y cualquier página asignada de Zygote que se haya modificado desde que Zygote bifurcó el proceso de la aplicación.

  • Asignación de montón

es la cantidad de memoria rastreada por Dalvik y el asignador de montón nativo para su aplicación. Este valor es mayor que Pss Total y Private Dirty porque su proceso se bifurca de Zygote y contiene asignaciones que su proceso comparte con todos los demás procesos.

  • .so mmap y .dex mmap

RAM ocupada por código mapeado .so (nativo) y .dex (Dalvik o ART). El valor de Pss Total incluye el código de plataforma compartido entre aplicaciones; Private Clean es el propio código de su aplicación. Por lo general, la memoria mapeada real es más grande: la RAM aquí es solo la RAM requerida actualmente por el código que está ejecutando la aplicación. Sin embargo, los .so mmaps tienen RAM sucia privada más grande porque el código nativo se modifica cuando se carga en su dirección final.

  • mapa de avena

Esta es la cantidad de RAM utilizada por la imagen del código, calculada en base a clases precargadas comúnmente utilizadas por varias aplicaciones. Esta imagen se comparte entre todas las aplicaciones y no se ve afectada por una aplicación específica.

  • mapa de arte

Esta es la cantidad de RAM ocupada por la imagen del montón, calculada en base a clases precargadas comúnmente utilizadas por varias aplicaciones. Esta imagen se comparte entre todas las aplicaciones y no se ve afectada por una aplicación específica. Aunque una imagen ART contiene instancias de objetos, aún no cuenta para el tamaño de almacenamiento dinámico.

But as to what the difference is between "Pss", "PrivateDirty", and "SharedDirty"... well now the fun begins.

A lot of memory in Android (and Linux systems in general) is actually shared across multiple processes. 
So how much memory a processes uses is really not clear. Add on top of that paging out to disk (let alone swap which we don't use on 
Android) and it is even less clear.

Thus if you were to take all of the physical RAM actually mapped in to each process, and add up all of the processes, 
you would probably end up with a number much greater than the actual total RAM.

The Pss number is a metric the kernel computes that takes into account memory sharing -- basically each page of RAM in a process is 
scaled by a ratio of the number of other processes also using that page. This way you can (in theory) add up the pss across all 
processes to see the total RAM they are using, and compare pss between processes to get a rough idea of their relative weight.

The other interesting metric here is PrivateDirty, which is basically the amount of RAM inside the process that can not be paged 
to disk (it is not backed by the same data on disk), and is not shared with any other processes. Another way to look at this is the 
RAM that will become available to the system when that process goes away (and probably quickly subsumed into caches and other uses 
of it).

Aprendido de este artículo:

Muchos procesos en los sistemas generales de Android y Linux compartirán algo de memoria, por lo que la memoria utilizada por un proceso en realidad no está muy clara, por lo que si agrega la memoria realmente ocupada por cada proceso, puede encontrar que el resultado será mucho más que el mem total real.

Pss es el valor calculado por el kernel basado en la memoria compartida, y el valor de Pss es un cierto porcentaje de la memoria compartida. De esta forma, el valor de RAM total se obtiene sumando los Pss de todos los procesos, y la tasa de uso de estos procesos también se puede obtener a través del valor de Pss entre procesos.

PrivateDirty, que es básicamente memoria dentro de un proceso que no se puede paginar en el disco y no se comparte con otros procesos. Otra forma de ver el uso de la memoria de un proceso es cuando finaliza el proceso, el cambio de la memoria disponible del sistema (también se puede fusionar rápidamente en el caché u otros procesos que usan el área de memoria).

 其他类型              smap 路径名称                       描述
 
Ashmem              /dev/ashmem            匿名共享内存用来提供共享内存通过分配一个多个进程
                                                         可以共享的带名称的内存块
Other dev            /dev/                         内部driver占用的在 “Other dev”                                                 
.so mmap             .so                           C 库代码占用的内存
.jar mmap            .jar                          Java 文件代码占用的内存
.apk mmap            .apk                          apk代码占用的内存
.ttf mmap            .ttf                          ttf 文件代码占用的内存
.dex mmap            .dex                          Dex 文件代码占用的内存
Other mmap                                         其他文件占用的内存 

6.2 Estadísticas de meminfo del sistema

Total RAM: 3,768,168K (status normal)
 Free RAM: 2,186,985K (   64,861K cached pss +   735,736K cached kernel + 1,386,388K free)
      ION:    58,408K (   53,316K mapped +      -128K unmapped +     5,220K pools)
 Used RAM: 1,440,349K (1,116,469K used pss +   323,880K kernel)
 Lost RAM:   140,822K
     ZRAM:        12K physical used for         0K in swap (2,097,148K total swap)
   Tuning: 256 (large 512), oom   640,000K, restore limit   213,333K (high-end-gfx)

6.2.1 RAM total

pw.print(stringifyKBSize(memInfo.getTotalSizeKb()));

La RAM total es MemTotal en /proc/meminfo

6.2.2  RAM libre

pw.print(stringifyKBSize(cachedPss + memInfo.getCachedSizeKb()
                                       + memInfo.getFreeSizeKb()));

 Entre paréntesis:

  • cached pss:Todos los pss del proceso oom_score_adj >= 900
  • kernel en caché:/proc/meminfo.Buffers + /proc/meminfo.KReclaimable + /proc/meminfo.Cached - /proc/meminfo.Mapped
  • gratis:/proc/meminfo.MemFree

6.2.3 ION

  • tamaño del montón de iones: 读取 /sys/kernel/ion/total_heaps_kb
  • tamaño del grupo de iones: leer /sys/kernel/ion/total_pools_kb
  • ion mapeado + ion no mapeado = montón de iones

6.2.4 RAM utilizada

pw.print(stringifyKBSize(totalPss - cachedPss + kernelUsed)); 

 entre paréntesis

  • pss usado:totalPss - cachedPss
  • KernelUsed:/proc/meminfo.Shmem + /proc/meminfo.SlabUnreclaim + VmallocUsed + /proc/meminfo.PageTables + /proc/meminfo.KernelStack + [ionHeap]

Preste atención al KernelStack anterior, solo cuando el kernel no esté configurado con  CONFIG_VMAP_STACK , se agregará.

frameworks/base/core/java/com/android/internal/util/MemInfoReader.java

    public long getKernelUsedSizeKb() {
        long size = mInfos[Debug.MEMINFO_SHMEM] + mInfos[Debug.MEMINFO_SLAB_UNRECLAIMABLE]
                + mInfos[Debug.MEMINFO_VM_ALLOC_USED] + mInfos[Debug.MEMINFO_PAGE_TABLES];
        if (!Debug.isVmapStack()) {
            size += mInfos[Debug.MEMINFO_KERNEL_STACK];
        }
        return size;
    }

 6.2.5 RAM perdida

            final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
                    - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
                    - kernelUsed - memInfo.getZramTotalSizeKb();

 RAM perdida = proc/meminfo.Memtotal - (totalPss - totalSwapPss) - /proc/meminfo.Memfree - /proc/meminfo.Cached - kernel usado - zram usado

Aviso:

Se puede inferir aproximadamente de aquí

RAM LIBRE + RAM UTILIZADA - totalSwapPss + RAM perdida + ZRAM = RAM total

6.2.6 ZRAM

  • Tamaño físico de zram: el tercer parámetro de /sys/block/zram0/mm_stat
  • total de intercambio:proc/meminfo.
  • libre de intercambio:proc/meminfo.SwapFree
  • canje usado: canje total - canje gratis

6.2.7 Afinación

        pw.print("   Tuning: ");
        pw.print(ActivityManager.staticGetMemoryClass());
        pw.print(" (large ");
        pw.print(ActivityManager.staticGetLargeMemoryClass());
        pw.print("), oom ");
        pw.print(stringifySize(
                    mProcessList.getMemLevel(ProcessList.CACHED_APP_MAX_ADJ), 1024));
        pw.print(", restore limit ");
        pw.print(stringifyKBSize(mProcessList.getCachedRestoreThresholdKb()));
        if (ActivityManager.isLowRamDeviceStatic()) {
            pw.print(" (low-ram)");
        }
        if (ActivityManager.isHighEndGfx()) {
            pw.print(" (high-end-gfx)");
        }
        pw.println();

grande: el valor de la propiedad dalvik.vm.heapsize, en MB

oom: el valor del último elemento de la matriz mOomMinFree en ProcessList

límite de restauración: el valor de la variable mCachedRestoreLevel en ProcessList, el valor máximo de un proceso desde el almacenamiento en caché hasta el fondo, generalmente 1/3 del último valor de mOomMinFree.

low-ram: si se trata de un dispositivo con poca memoria RAM, generalmente a través de prop ro.config.low_ram o prop debug.force_low_ram cuando ro.debuggable está habilitado.

high-end-gfx: ro.config.low_ram es falso, y ro.config.avoid_gfx_accel es falso, y el valor de config_avoidGfxAccel es falso.

Referencia: https://blog.csdn.net/feelabclihu/article/details/105534175

Supongo que te gusta

Origin blog.csdn.net/jingerppp/article/details/126269031
Recomendado
Clasificación