Android 7.1 设置-内存

简介: Android 7.1 设置-内存

平台


    RK3288 + Android 7.1


概述


查看系统内存使用情况, 如下图所示:

image.png


流程解读


一些字符显示

1.

image.png

2.

image.png


packages/apps/Settings/AndroidManifest.xml [入口]


 

<activity android:name="Settings$MemorySettingsActivity"
                android:label="@string/memory_settings_title"
                android:icon="@drawable/ic_settings_memory"
                android:taskAffinity="">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="com.android.settings.SHORTCUT" />
            </intent-filter>
            <intent-filter android:priority="3">
                <action android:name="com.android.settings.action.SETTINGS" />
            </intent-filter>
            <meta-data android:name="com.android.settings.category"
                android:value="com.android.settings.category.device" />
            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
                android:value="com.android.settings.applications.ProcessStatsSummary" />
        </activity>


相关源码

packages/apps/Settings/src/com/android/settings/applications/ProcessStatsSummary.java

packages/apps/Settings/src/com/android/settings/applications/ProcessStatsBase.java

packages/apps/Settings/src/com/android/settings/applications/ProcStatsData.java

packages/apps/Settings/src/com/android/settings/applications/ProcStatsPackageEntry.java

packages/apps/Settings/src/com/android/settings/applications/ProcessStatsUi.java

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

frameworks/base/core/java/com/android/internal/app/procstats/ProcessStats.java

image.png

image.png

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


public ParcelFileDescriptor getStatsOverTime(long minTime) {
        mAm.mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.PACKAGE_USAGE_STATS, null);
        Parcel current = Parcel.obtain();
        long curTime;
        synchronized (mAm) {
            long now = SystemClock.uptimeMillis();
            mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
            mProcessStats.mTimePeriodEndUptime = now;
            mProcessStats.writeToParcel(current, now, 0);
            curTime = mProcessStats.mTimePeriodEndRealtime
                    - mProcessStats.mTimePeriodStartRealtime;
        }
        mWriteLock.lock();
        try {
            if (curTime < minTime) {
                // Need to add in older stats to reach desired time.
                ArrayList<String> files = getCommittedFiles(0, false, true);
                if (files != null && files.size() > 0) {
                    current.setDataPosition(0);
                    ProcessStats stats = ProcessStats.CREATOR.createFromParcel(current);
                    current.recycle();
                    int i = files.size()-1;
                    while (i >= 0 && (stats.mTimePeriodEndRealtime
                            - stats.mTimePeriodStartRealtime) < minTime) {
                        AtomicFile file = new AtomicFile(new File(files.get(i)));
                        i--;
                        ProcessStats moreStats = new ProcessStats(false);
                        readLocked(moreStats, file);
                        if (moreStats.mReadError == null) {
                            stats.add(moreStats);
                            StringBuilder sb = new StringBuilder();
                            sb.append("Added stats: ");
                            sb.append(moreStats.mTimePeriodStartClockStr);
                            sb.append(", over ");
                            TimeUtils.formatDuration(moreStats.mTimePeriodEndRealtime
                                    - moreStats.mTimePeriodStartRealtime, sb);
                            Slog.i(TAG, sb.toString());
                        } else {
                            Slog.w(TAG, "Failure reading " + files.get(i+1) + "; "
                                    + moreStats.mReadError);
                            continue;
                        }
                    }
                    current = Parcel.obtain();
                    stats.writeToParcel(current, 0);
                }
            }
            final byte[] outData = current.marshall();
            current.recycle();
            final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
            Thread thr = new Thread("ProcessStats pipe output") {
                public void run() {
                    FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]);
                    try {
                        fout.write(outData);
                        fout.close();
                    } catch (IOException e) {
                        Slog.w(TAG, "Failure writing pipe", e);
                    }
                }
            };
            thr.start();
            return fds[0];
        } catch (IOException e) {
            Slog.w(TAG, "Failed building output pipe", e);
        } finally {
            mWriteLock.unlock();
        }
        return null;
    }
    private ArrayList<String> getCommittedFiles(int minNum, boolean inclCurrent,
            boolean inclCheckedIn) {
        File[] files = mBaseDir.listFiles();
        if (files == null || files.length <= minNum) {
            return null;
        }
        ArrayList<String> filesArray = new ArrayList<String>(files.length);
        String currentFile = mFile.getBaseFile().getPath();
        if (DEBUG) Slog.d(TAG, "Collecting " + files.length + " files except: " + currentFile);
        for (int i=0; i<files.length; i++) {
            File file = files[i];
            String fileStr = file.getPath();
            if (DEBUG) Slog.d(TAG, "Collecting: " + fileStr);
            if (!inclCheckedIn && fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX)) {
                if (DEBUG) Slog.d(TAG, "Skipping: already checked in");
                continue;
            }
            if (!inclCurrent && fileStr.equals(currentFile)) {
                if (DEBUG) Slog.d(TAG, "Skipping: current stats");
                continue;
            }
            filesArray.add(fileStr);
        }
        Collections.sort(filesArray);
        return filesArray;
    }


mBaseDir 是由ActivityManagerService 创建ProcessStatsService时传进来的:


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


// Note: This method is invoked on the main thread but may need to attach various
    // handlers to other threads.  So take care to be explicit about the looper.
    public ActivityManagerService(Context systemContext) {
        //.......
        // TODO: Move creation of battery stats service outside of activity manager service.
        File dataDir = Environment.getDataDirectory();
        File systemDir = new File(dataDir, "system");
        mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));
    }


最终可以看到, ProcessStatsService会去读取data/system/procstats目录下的文件, 并解析传递数据


rk3288:/data/system/procstats # ll
total 160
-rw------- 1 system system 11276 2013-01-19 13:45 state-2013-01-19-10-44-19.bin
-rw------- 1 system system  7684 2013-01-19 16:47 state-2013-01-19-13-45-00.bin
-rw------- 1 system system  7508 2013-01-19 19:49 state-2013-01-19-16-47-00.bin
-rw------- 1 system system  7508 2013-01-19 22:50 state-2013-01-19-19-49-00.bin
-rw------- 1 system system  7912 2013-01-20 01:52 state-2013-01-19-22-50-00.bin
-rw------- 1 system system  7896 2013-01-20 04:54 state-2013-01-20-01-52-00.bin
-rw------- 1 system system  8280 2013-01-20 07:56 state-2013-01-20-04-54-00.bin
-rw------- 1 system system  7672 2013-01-20 10:58 state-2013-01-20-07-56-00.bin
-rw------- 1 system system  7656 2013-01-20 11:58 state-2013-01-20-10-58-00.bin


procstats文件的读取:


static byte[] readFully(InputStream stream, int[] outLen) throws IOException {
        int pos = 0;
        final int initialAvail = stream.available();
        byte[] data = new byte[initialAvail > 0 ? (initialAvail+1) : 16384];
        while (true) {
            int amt = stream.read(data, pos, data.length-pos);
            if (DEBUG_PARCEL) Slog.i("foo", "Read " + amt + " bytes at " + pos
                    + " of avail " + data.length);
            if (amt < 0) {
                if (DEBUG_PARCEL) Slog.i("foo", "**** FINISHED READING: pos=" + pos
                        + " len=" + data.length);
                outLen[0] = pos;
                return data;
            }
            pos += amt;
            if (pos >= data.length) {
                byte[] newData = new byte[pos+16384];
                if (DEBUG_PARCEL) Slog.i(TAG, "Copying " + pos + " bytes to new array len "
                        + newData.length);
                System.arraycopy(data, 0, newData, 0, pos);
                data = newData;
            }
        }
    }
    public void read(InputStream stream) {
        try {
            int[] len = new int[1];
            byte[] raw = readFully(stream, len);
            Parcel in = Parcel.obtain();
            in.unmarshall(raw, 0, len[0]);
            in.setDataPosition(0);
            stream.close();
            readFromParcel(in);
        } catch (IOException e) {
            mReadError = "caught exception: " + e;
        }
    }


扩展


dumpsys procstats详解

查看 RAM 使用情况数据 (procstats)

0a2653c851af460fa595bd959398a8f1.png

使用内存性能分析器查看应用的内存使用情况



相关文章
|
2月前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
359 1
|
3月前
|
存储 前端开发 Java
Android MVVM架构模式下如何避免内存泄漏
Android采用MVVM架构开发项目,如何避免内存泄漏风险?怎样避免内存泄漏?
121 1
|
5月前
|
XML API Android开发
码农之重学安卓:利用androidx.preference 快速创建一、二级设置菜单(demo)
本文介绍了如何使用androidx.preference库快速创建具有一级和二级菜单的Android设置界面的步骤和示例代码。
155 1
码农之重学安卓:利用androidx.preference 快速创建一、二级设置菜单(demo)
|
19天前
|
运维 监控 Ubuntu
【运维】如何在Ubuntu中设置一个内存守护进程来确保内存不会溢出
通过设置内存守护进程,可以有效监控和管理系统内存使用情况,防止内存溢出带来的系统崩溃和服务中断。本文介绍了如何在Ubuntu中编写和配置内存守护脚本,并将其设置为systemd服务。通过这种方式,可以在内存使用超过设定阈值时自动采取措施,确保系统稳定运行。
44 4
|
1月前
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
|
2月前
|
监控 Java Android开发
深入探讨Android系统的内存管理机制
本文将深入分析Android系统的内存管理机制,包括其内存分配、回收策略以及常见的内存泄漏问题。通过对这些方面的详细讨论,读者可以更好地理解Android系统如何高效地管理内存资源,从而提高应用程序的性能和稳定性。
84 16
|
2月前
|
Android开发 开发者
Android性能优化——内存管理的艺术
Android性能优化——内存管理的艺术
|
2月前
|
弹性计算 Kubernetes Perl
k8s 设置pod 的cpu 和内存
在 Kubernetes (k8s) 中,设置 Pod 的 CPU 和内存资源限制和请求是非常重要的,因为这有助于确保集群资源的合理分配和有效利用。你可以通过定义 Pod 的 `resources` 字段来设置这些限制。 以下是一个示例 YAML 文件,展示了如何为一个 Pod 设置 CPU 和内存资源请求(requests)和限制(limits): ```yaml apiVersion: v1 kind: Pod metadata: name: example-pod spec: containers: - name: example-container image:
275 1
|
3月前
|
编解码 Android开发 UED
构建高效Android应用:从内存优化到用户体验
【10月更文挑战第11天】本文探讨了如何通过内存优化和用户体验改进来构建高效的Android应用。介绍了使用弱引用来减少内存占用、懒加载资源以降低启动时内存消耗、利用Kotlin协程进行异步处理以保持UI流畅,以及采用响应式设计适配不同屏幕尺寸等具体技术手段。
58 2
|
4月前
|
Java 测试技术 Android开发
Android性能测试——发现和定位内存泄露和卡顿
本文详细介绍了Android应用性能测试中的内存泄漏与卡顿问题及其解决方案。首先,文章描述了使用MAT工具定位内存泄漏的具体步骤,并通过实例展示了如何分析Histogram图表和Dominator Tree。接着,针对卡顿问题,文章探讨了其产生原因,并提供了多种测试方法,包括GPU呈现模式分析、FPS Meter软件测试、绘制圆点计数法及Android Studio自带的GPU监控功能。最后,文章给出了排查卡顿问题的四个方向,帮助开发者优化应用性能。
239 4
Android性能测试——发现和定位内存泄露和卡顿

热门文章

最新文章