dumpsys meminfo ausführliche Erklärung

Quellcode basiert auf: Android R

0. Vorwort

Tatsächlich wurde dumpsys meminfo vor langer Zeit  im Artikel zum Anzeigen der Speichernutzung in Android analysiert , aber als ich kürzlich die Speicherdaten gezählt habe, habe ich festgestellt, dass sie nicht korrekt sind, also habe ich den Quellcode erneut analysiert Beim  Anzeigen der Speichernutzung in Android In diesem Blogbeitrag wird der Prozess von meminfo service and dump unter AMS in Kombination mit dem Code detailliert analysiert.

1. Der Ausgangspunkt von meminfo dumpsys

Die Meminfo-Statistiken unter AMS werden über den dumpsys-Befehl ausgegeben, der in der bin-Datei unter /system/bin/ gespeichert ist. Das Quellcode-Verzeichnis befindet sich unter frameworks/native/cmds/dumpsys/ Details entnehmen Sie bitte  dem dumpsys- Artikel in Android .

2. meminfo-Dienste – MemBinder

Die Dienste, die ausgegeben werden können, werden alle im ServiceManager hinzugefügt, beispielsweise wird meminfo in der Funktion setSystemProcess von frameworks/base/services/java/com/android/server/am/ActivityManagerService.java hinzugefügt:

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);

            ...
}

 Notiz:

 Durch  step7 des dumpsys-Artikels in android wissen wir, dass das Dump-Flag angegeben werden muss, wenn ein Dienst (z. B. meminfo) eine Dump-Operation über den dumpsys-Befehl ausführen muss. Hier gibt meminfo das Dump-Flag als DUMP_FLAG_PRIORITY_HIGH an , wenn addService  .

Schauen Sie unten:

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);
            }
        }
    }

Darin sind zwei Member-Variablen definiert:

  • mActivityManagerService: AMS-Objekte aufzeichnen;
  • mPriorityDumper: Verbinden Sie sich über seine Schnittstelle dump() mit AMS.dumpApplicationMemoryUsage();

Die eigentliche Implementierung befindet sich in dumpApplicationMemoryUsage() von AMS.

3. dumpsys meminfo -h

Nachdem Sie dumpApplicationMemoryUsage() eingegeben haben, sehen Sie eine While-Schleife, um die an dumpsys meminfo angehängten Parameter zu analysieren. Sehen Sie sich hier zuerst -h an und verwenden Sie diesen Parameter, um andere Parameteroptionen von dumpsys meminfo besser zu verstehen.

Der Code wird hier nicht gepostet, schauen Sie sich einfach die Ausgabe des Terminals an:

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: Enthält alle verfügbaren Informationen, genauer gesagt enthält es -d, -s, -S;
  • -d: muss Dalvik-Details enthalten;
  • -c: Ausgabe in eine komprimierte, maschinenlesbare Darstellung;
  • -s: Nur die Zusammenfassung des Anwendungsspeichers ausgeben;
  • -S: Speichere die Swap-PSS-Informationen;
  • --oom: nur die OOM adj-Informationen von RSS/PSS ausgeben;
  • --local: Informationen nur lokal sammeln und nur wirksam werden, wenn dies durch -a oder -s angegeben wird;
  • --package: Alle Prozesse ausgeben, die das angegebene Paket laden;
  • --checkin: Daten zum Einchecken ausgeben;
  • --proto: proto-Daten ausgeben;
  • Auf dumpsys meminfo kann [Prozess] folgen, dieser Prozess kann der Prozessname oder die Prozess-PID sein;

4. CollectProcesses()

Nachdem die Befehlszeilenparameter von dumpsys meminfo analysiert wurden, wird collectProcesses() aufgerufen, um die Pakete oder PIDs zu bestätigen, die mit dem Befehl übereinstimmen:

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;
    }

Der Code ist noch relativ klar:

  • Wenn die Befehlszeile pid angibt, dann sammeln Sie diese Prozesse;
  • Wenn packageName festgelegt ist, sammeln Sie diese Pakete;
  • Wenn nicht gesetzt, alle LRU-Prozesse erfassen;

Beachten Sie, dass die in den ersten beiden Punkten gesammelte Prozedur möglicherweise leer ist, da die eingestellten Parameter möglicherweise falsch sind oder nicht zugeordnet werden können.

Zu diesem Zeitpunkt fordert das Terminal auch No process auf:

shift:/ # dumpsys meminfo 12345
Kein Prozess gefunden für: 12345

5. dumpApplicationMemoryUsage()

Die Menge an Code für diese Funktion ist zu groß, also analysieren wir hier die wichtigsten Punkte.

5.1 Mehrere Variablen 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();
                }

Ganz am Anfang müssen Sie einige wichtige Initialisierungen beachten:

  • Thread: Geben Sie IApplicationThread an.Wenn --local nicht gesetzt ist (die meisten davon werden nicht gesetzt), müssen die anwendungsseitigen Daten durch diesen Thread gelesen   und durch Pipe an AMS übergeben werden .
  • oomAdj: ein wichtiger Datensatz in dumpsys meminfo, für LMKD siehe den Artikel über die Algorithmusanalyse von adj score im Detail;
  • pid: die pid der aktuellen Anwendung, sie wird zusammen mit dumpsys meminfo angezeigt;
  • mi: der Kern der Speicherdaten, diese Variable wird unten im Detail erklärt, siehe Abschnitt 5.2 für Details ;

5.2 Debug.MemoryInfo()

Quellverzeichnis: frameworks/base/core/java/android/os/Debug.java

Viele native Schnittstellen werden hier bereitgestellt:

    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 Debug.getMemoryInfo()

Dann schaut der Code in Abschnitt 5.1 weiter nach unten:

                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 wird hauptsächlich verwendet, um detaillierte Informationen der Anwendung zu erhalten. Im Allgemeinen wird diese Variable auf „true“ gesetzt, wenn „pid“ oder „package“ oder direkt der Befehlsparameter „-s“ angegeben wird;
  • Der Standardwert von brief ist false, der von MemBinder übergeben wird;
  • opts.oomOnly wird nur dann auf true gesetzt, wenn --oom angegeben ist;

Wenn --oom nicht angegeben ist, durchläuft der Code den if-Fall und die detaillierten Speicherinformationen des Prozesses werden über Debug.getMemoryInfo() abgerufen:

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;
}
  • Erhalten Sie die Speicherinformationen des Prozesses von /proc/ pid /smaps durch load_maps() ;
  • Erhalten Sie Informationen zum Grafikspeicher über libmemtrack.so durch read_memtrack_memory();
  • Setzen Sie die Gruppeninformationen von UNKNOWN, Dalvik und Heap auf Meminfo durch env->SetIntField()  ;
  • Andere Informationen über otherArray auf MemoryInfo.otherStats[] setzen;

5.3.1 load_maps()

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() ist eine libmeminfo.so-Schnittstelle, der Code befindet sich unter /system/memory/libmeminfo/.

Hier ist eine Zusammenfassung eines Call-Frame-Diagramms:

Er liest hauptsächlich den Prozess-smaps-Knoten. Entsprechend verschiedener Attribute wird der virtuelle Adressraum des Prozesses in mehrere VMAs aufgeteilt. Jeder VMA bildet eine doppelt verkettete Liste durch vm_next und vm_prev. Die verkettete Liste befindet sich in task_struct->mm_struct -> Mmap des Prozesses. Beim Lesen der smaps-Datei eines Prozesses über die proc-Schnittstelle findet der Kernel zuerst den Kopf der vma-Verknüpfungsliste des Prozesses, durchläuft jede vma in der verknüpften Liste, zählt die Verwendung dieser vma bis walk_page_vma und zeigt sie schließlich an .

Hier sind die Statistiken für einen der VMAs:

  • Rss: Residenter physischer Speicher, der physische Speicher, der tatsächlich vom Prozess im RAM gehalten wird. RSS enthält den von der gemeinsam genutzten Bibliothek belegten Speicher, daher kann dies irreführend sein;
  • Pss: anteilig verwendeter physikalischer Speicher, der Unterschied zwischen Pss und Rss besteht darin, dass Pss die durchschnittliche Speichernutzung gemeinsam genutzter Bibliotheken zählt. Wenn ein so 30 kb Speicher belegt und dieser so von 3 Prozessen geteilt wird, dann beträgt der von so belegte Speicher in der Statistik eines bestimmten Prozesses Pss 30/3 kb;
  • Private_Dirty: Private Speicherdaten, einfach nur Dirty, das Gegenteil von Private_Clean. Dirty umfasst page_dirty und pte_dirty, page_dirty ist die sogenannte Dirty Page (die Datei wird im Speicher gelesen und modifiziert, sie wird als Dirty Page markiert). Für pte_dirty, wenn die vma als anonym verwendet wird, wird do_anonymous_page aufgerufen, wenn das Lesen und Schreiben dieser vma einen Seitenfehler auslöst.Wenn vma_flags VM_WRITE enthält, wird es das pte_mkdirty(entry)-Flag übergeben;
  • Private_Clean: private saubere Daten, im Gegensatz zu Private_Dirty;
  • Shared_Dirty: Wie bei Private_Dirty wird der Speicher von mindestens einem anderen Prozess referenziert, und mindestens ein Prozess modifiziert ihn;
  • Shared_Clean: Dasselbe wie Private_Clean, im Gegensatz zu Shared_Dirty;
  • Swap: Die auszutauschende native Seite kann SwapRss heißen;
  • SwapPss: Native Seiten, die getauscht werden, gezählt nach Verhältnis;

Im Allgemeinen ist es in Android ZRAM, das die Menge an verfügbarem Speicher im System erhöht, indem Speicherseiten komprimiert und in einen dynamisch zugewiesenen Speicherauslagerungsbereich gestellt werden. Die komprimierten Seiten sind alle anonyme Seiten.

Aber der folgende Abschnitt von vma ist ein Datei-Mapping, aber es gibt auch ein Swap-Feld, weil diese Datei durch mmap in den Adressraum des Prozesses übertragen wird. Wenn das Tag MAP_PRIVATE enthält, bedeutet dies, dass es sich um eine Copy-on-Write-Zuordnung handelt.Obwohl es dateigestützt ist, werden die Daten beim Schreiben von Daten in diese Daten auf die anonyme Seite kopiert, siehe also oben Anonymous : Es ist auch 0.

5.3.2 Vergleich zwischen vma- und HEAP-Enumeration in smaps

[Haufen]

[anon:libc_malloc]

[anon:schild:

[Anon: GWP-ASan

HEAP_NATIVE

[anon:dalvik-*

HEAP_DALVIK_OTHER
*.So HEAP_SO
*.Krug HEAP_JAR
*.apk HEAP_APK
*.ttf HEAP_TTF

*.odex (*.dex)

HEAP_DEX

----HEAP_DEX_APP_DEX

*.vdex (@boot /boot /apex)

HEAP_DEX

----HEAP_DEX_BOOT_VDEX

----HEAP_DEX_APP_VDEX

*.Hafer HEAP_OAT

*.Kunst

*.art] (@boot /boot /apex)

HEAP_ART

----HEAP_ART_BOOT

----HEAP_ART_APP

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

/dev/ashmem/jit-zygote-cache

/memfd:jit-cache

/memfd:jit-zygote-cache

HEAP_DALVIK_OTHER
/dev/ashm HEAP_ASHMEM

Siehe die Funktion load_maps() für detaillierte Informationen zu which_heap und sub_heap.

5.3.3 read_memtrack_memory()

Rufen Sie über diese Funktion den zugewiesenen Speicher des Prozesses auf der GPU ab.

Das Folgende ist das Anrufrahmendiagramm:

 Das obige Bild liest den vom Prozess zugewiesenen Speicher auf der GPU aus, und jeder Hersteller kann unterschiedliche statistische Strategien haben, was auch der Grund für die HAL-Schicht ist.


5.4 thread.dumpMemInfo()

In Abschnitt 5.1 sind mehrere wichtige Variablen aufgelistet, von denen eine IApplicationThread ist, die für jeden Prozess einzigartig ist.

Dies ist natürlich der Fall, wenn opts.dumpDetails wahr ist, dh meminfo für eine einzelne Anwendung;

       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();
            }

Erstellen Sie ein TransferPipe-Objekt, das einen Thread und eine Pipe erstellt. Schreiben Sie dann Fd in den ActivithThread des App-Prozesses, und der ActivityThread analysiert die Speichernutzung des App-Prozesses. Wenn die Funktion go() aufgerufen wird, wird der von TransferPipe erstellte Thread gestartet und wartet auf die Pipe-Kommunikation.Wenn AMS die Daten über readFd erhält, benachrichtigt es den dumpsys- Prozess, um anzuzeigen, dass der Dump abgeschlossen ist.

Schauen wir uns dumpMemInfo() an:

 ---->

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);
            }
        }

Der detaillierte Code wird hier nicht weiter analysiert, aber ein Call-Frame-Diagramm zusammengefasst:

In dumpMeminfo() werden totalMemory und freeMemory des App-Prozesses dalvik über getRuntime() abgerufen, und dalvikAllocated wird berechnet, um die Speichernutzung der virtuellen Maschine des App-Prozesses zu erhalten.

Und verwenden Sie drei native Schnittstellen wie Debug.getNativeHeapSize(), um die native Nutzung des App-Prozesses zu zählen. Hier ist dasselbe wie in Abschnitt 5.3 oben, und es wird immer noch androi_os_Debug.cpp eingetragen:

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() gibt Statistiken zur Speicherzuweisung zurück. Die Funktion ist in android/bionic/libc/include/malloc.h deklariert und die Funktion ist in android/bionic/libc/bionic/malloc_common.cpp definiert:

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

mallinfo() gibt hauptsächlich eine Struktur zurück, die die Speicherinformationen enthält, die von malloc() und den zugehörigen Funktionsaufrufen angefordert werden. Im Folgenden sind die spezifischen Informationen der Struktur mallinfo aufgeführt (siehe man für weitere Informationen):

   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) */
   };

Die drei Informationen, die wir hier zurückgeben:

  • usmblks: der maximale Gesamtspeicher von alloc (Einheit: Byte);
  • uordblks: Gesamtzuweisungsspeicher (Einheit: Byte);
  • fordblks: Gesamter freier Speicher (Einheit: Byte);

 Diese beiden Eingänge sind in der folgenden Abbildung dargestellt: 

5.5 MemInfoReader

Bevor Sie MemInfoReader verwenden, müssen Sie zum Anfang des Codes zurückkehren und die Variable collectNative verstehen:

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

Beim Ausgeben der Meminfo mehrerer Anwendungen oder aller Anwendungen wird die Variable collectNative auf true gesetzt; wenn nur die Meminfo einer einzelnen Anwendung gedruckt wird, ist der Wert falsch, sodass sie am Ende nicht gedruckt wird.

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

Der detaillierte Code wird nicht mehr analysiert, hier eine Zusammenfassung eines aufrufenden Frames:

Die Ausgabe ist wie folgt:

6. meminfo-Datenanalyse

6.1 meminfo für eine einzelne Anwendung

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

Werfen wir einen Blick auf einige der wichtigsten Konzepte:

           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

  • Dalvik Haufen

Von Dalvik-Zuweisungen in der Anwendung verwendeter RAM. Pss Total umfasst alle Zygote-Zuweisungen (gemessen an der Menge des gemeinsam genutzten Speichers zwischen Prozessen, wie in der PSS-Definition oben beschrieben). Die private Dirty-Nummer ist tatsächlicher RAM, der nur dem Heap Ihrer App zugewiesen ist und aus Ihren eigenen Zuweisungen und allen von Zygote zugewiesenen Seiten besteht, die geändert wurden, seit Zygote den App-Prozess geforkt hat.

  • Heap Alloc

ist die Speichermenge, die von Dalvik und dem nativen Heap-Allokator für Ihre Anwendung verfolgt wird. Dieser Wert ist größer als „Pss Total“ und „Private Dirty“, da Ihr Prozess von Zygote abzweigt und Zuweisungen enthält, die Ihr Prozess mit allen anderen Prozessen teilt.

  • .so mmap und .dex mmap

RAM belegt durch gemappten .so (nativ) und .dex (Dalvik oder ART) Code. Der Pss-Gesamtwert umfasst Plattformcode, der zwischen Apps geteilt wird; Private Clean ist der eigene Code Ihrer App. In der Regel ist der tatsächlich zugeordnete Speicher größer – der Arbeitsspeicher ist hier nur der Arbeitsspeicher, der derzeit von dem Code benötigt wird, den die App ausführt. .so mmaps haben jedoch einen größeren privaten Dirty RAM, da nativer Code modifiziert wird, wenn er in seine endgültige Adresse geladen wird.

  • .hafer mmap

Dies ist die Menge an RAM, die vom Code-Image verwendet wird, berechnet basierend auf vorgeladenen Klassen, die üblicherweise von mehreren Anwendungen verwendet werden. Dieses Bild wird von allen Anwendungen gemeinsam genutzt und wird nicht von einer bestimmten Anwendung beeinflusst.

  • .art mmap

Dies ist die vom Heap-Image belegte RAM-Größe, die auf der Grundlage vorab geladener Klassen berechnet wird, die üblicherweise von mehreren Anwendungen verwendet werden. Dieses Bild wird von allen Anwendungen gemeinsam genutzt und wird nicht von einer bestimmten Anwendung beeinflusst. Obwohl ein ART-Bild Objektinstanzen enthält, wird es dennoch nicht auf Ihre Heap-Größe angerechnet.

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).

Aus diesem Artikel gelernt:

Viele Prozesse in den allgemeinen Android- und Linux-Systemen teilen sich einen Teil des Arbeitsspeichers, sodass der von einem Prozess verwendete Arbeitsspeicher tatsächlich nicht sehr klar ist. Wenn Sie also den Arbeitsspeicher addieren, der tatsächlich von jedem Prozess belegt ist, werden Sie möglicherweise feststellen, dass das Ergebnis weitaus größer sein wird als Der tatsächliche Gesamtspeicher.

Pss ist der Wert, der vom Kernel basierend auf dem gemeinsam genutzten Speicher berechnet wird, und der Wert von Pss ist ein bestimmter Prozentsatz des gemeinsam genutzten Speichers. Auf diese Weise wird der gesamte RAM-Wert durch Addieren der Pss aller Prozesse erhalten, und das Nutzungsverhältnis dieser Prozesse kann auch durch den Interprozess-Pss-Wert erhalten werden.

PrivateDirty, bei dem es sich im Grunde um Speicher innerhalb eines Prozesses handelt, der nicht auf die Festplatte ausgelagert werden kann und nicht mit anderen Prozessen geteilt wird. Eine andere Möglichkeit, die Speichernutzung eines Prozesses zu betrachten, ist, wenn der Prozess endet, die Änderung des verfügbaren Speichers des Systems (er kann auch schnell in den Cache oder andere Prozesse, die den Speicherbereich verwenden, zusammengeführt werden).

 其他类型              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 System-Meminfo-Statistiken

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 Gesamt-RAM

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

Gesamt-RAM ist MemTotal in /proc/meminfo

6.2.2  Freier Arbeitsspeicher

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

 In Klammern:

  • cached pss:Alle pss des Prozesses oom_score_adj >= 900
  • zwischengespeicherter Kernel: /proc/meminfo.Buffers + /proc/meminfo.KReclaimable + /proc/meminfo.Cached - /proc/meminfo.Mapped
  • kostenlos:/proc/meminfo.MemFree

6.2.3 ION

  • Ionenheapgröße: 读取 /sys/kernel/ion/total_heaps_kb
  • Ionenpoolgröße: Lesen Sie /sys/kernel/ion/total_pools_kb
  • abgebildetes Ion + nicht abgebildetes Ion = Ionenhaufen

6.2.4 Benutzter Arbeitsspeicher

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

 in Klammern

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

Achten Sie auf den obigen KernelStack, nur wenn der Kernel nicht mit  CONFIG_VMAP_STACK konfiguriert ist , wird er hinzugefügt.

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 Verlorener RAM

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

 Verlorener RAM = proc/meminfo.Memtotal – (totalPss – totalSwapPss) – /proc/meminfo.Memfree – /proc/meminfo.Cached – Kernel verwendet – zram verwendet

Notiz:

Daraus lässt sich grob ableiten

FREE RAM + USed RAM - totalSwapPss + Lost RAM + ZRAM = Total RAM

6.2.6 ZRAM

  • physische Größe von zram: der dritte Parameter von /sys/block/zram0/mm_stat
  • Swap total:proc/meminfo.SwapTotal
  • Swap free:proc/meminfo.SwapFree
  • Gebrauchter Tausch: Gesamttausch – kostenloser Tausch

6.2.7 Abstimmung

        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();

large: Der Wert der Eigenschaft dalvik.vm.heapsize in MB

oom: der Wert des letzten Elements des mOomMinFree-Arrays in ProcessList

Wiederherstellungslimit: Der Wert der mCachedRestoreLevel-Variablen in ProcessList, der maximale Wert eines Prozesses vom Cache zum Hintergrund, im Allgemeinen 1/3 des letzten Werts von mOomMinFree.

Low-RAM: Ob es sich um ein Low-RAM-Gerät handelt, im Allgemeinen über prop ro.config.low_ram oder prop debug.force_low_ram, wenn ro.debuggable aktiviert ist.

high-end-gfx: ro.config.low_ram ist falsch, und ro.config.avoid_gfx_accel ist falsch, und der Wert von config config_avoidGfxAccel ist falsch.

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

Ich denke du magst

Origin blog.csdn.net/jingerppp/article/details/126269031
Empfohlen
Rangfolge