【问题标题】:Get Memory Usage in Android在 Android 中获取内存使用情况
【发布时间】:2011-03-08 06:56:41
【问题描述】:

是否有任何API可以让我们获得android的CPU或内存使用情况?

我尝试过如下代码:

package com.infostretch.mainactivity;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class CPULoad 
{
    long total = 0;
    long idle = 0;

    float usage = 0;

    public CPULoad()
    {
        readUsage();
    }

    public float getUsage()
    {
        readUsage();
        return usage;
    }

    private void readUsage()
    {
        try
        {
            BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/stat")), 1000);
            String load = reader.readLine();
            reader.close();

            String[] toks = load.split(" ");

            long currTotal = Long.parseLong(toks[2]) + Long.parseLong(toks[3]) + Long.parseLong(toks[4]);
            long currIdle = Long.parseLong(toks[5]);

            this.usage = (currTotal - total) * 100.0f / (currTotal - total + currIdle - idle);
            this.total = currTotal;
            this.idle = currIdle;
        }
        catch(IOException ex)
        {
            ex.printStackTrace();
        }
    }
}

这是正确的做法吗?

【问题讨论】:

  • 也许你会接受一个答案...
  • o/p 我得到的不是正确的......一直 o/p 在 0.825699 到 1.0 的范围内,我的安卓手机上只有一个应用程序正在运行。我从 google play 下载了免费应用程序以检查 CPU 使用情况,但两者的 o/p 不同。你能告诉我我从 tv.setText(" "+readCPUUsage()); 得到什么 o/p
  • Android Studio 现在有一个内存选项卡,可以让您获取有关应用运行的所有信息。

标签: android cpu-usage


【解决方案1】:

我使用这个函数来计算 CPU 使用率。希望对你有帮助。

private float readUsage() {
    try {
        RandomAccessFile reader = new RandomAccessFile("/proc/stat", "r");
        String load = reader.readLine();

        String[] toks = load.split(" +");  // Split on one or more spaces

        long idle1 = Long.parseLong(toks[4]);
        long cpu1 = Long.parseLong(toks[2]) + Long.parseLong(toks[3]) + Long.parseLong(toks[5])
              + Long.parseLong(toks[6]) + Long.parseLong(toks[7]) + Long.parseLong(toks[8]);

        try {
            Thread.sleep(360);
        } catch (Exception e) {}

        reader.seek(0);
        load = reader.readLine();
        reader.close();

        toks = load.split(" +");

        long idle2 = Long.parseLong(toks[4]);
        long cpu2 = Long.parseLong(toks[2]) + Long.parseLong(toks[3]) + Long.parseLong(toks[5])
            + Long.parseLong(toks[6]) + Long.parseLong(toks[7]) + Long.parseLong(toks[8]);

        return (float)(cpu2 - cpu1) / ((cpu2 + idle2) - (cpu1 + idle1));

    } catch (IOException ex) {
        ex.printStackTrace();
    }

    return 0;
} 

【讨论】:

  • 什么?此代码适用于任意数量的处理器,并给出所有处理器组合的 cpu 使用率。
  • @KhurramMajeed 我最终没有保留我的代码,因为不需要核心 CPU。不过没多久就写完了。您需要知道的第一件事是 CPU 内核的数量。这个问题有一个功能可以做到这一点。 stackoverflow.com/questions/7962155/… ,然后您使用上面的代码,但忽略第一行。然后有一个循环,将每个核心和空闲的 CPU 记录到两个数组列表中。让你的线程休眠一会儿,然后有另一个循环记录每个内核的 CPU 和空闲状态。
  • 如果这个更容易访问就更好了,这是一个非常昂贵的功能(根据我的测量大约需要 350 毫秒)
  • 这需要时间,因为调用了 Thread.sleep()。必须有一个持续时间来计算 CPU 使用率。您可以将此代码放在后台线程中。
  • o/p 我得到的不是正确的......一直 o/p 在 0.825699 到 1.0 的范围内,我的安卓手机上只有一个应用程序正在运行。我从 google play 下载了免费应用程序以检查 CPU 使用情况,但两者的 o/p 不同。你能告诉我我从 tv.setText(" "+readCPUUsage()); 得到什么 o/p
【解决方案2】:

检查 CPU 使用率的一种简单方法是使用带有 top 的 adb 工具。即:

adb shell top -m 10

【讨论】:

  • 你不是说:“adb shell top -n 1”吗?
  • 虽然这是正确的,但我的问题是关于 Android API 而不是任何工具
  • 不是关于内存使用的问题吗,伙计们?
【解决方案3】:

根据前面的回答和个人经验,下面是我用来监控 CPU 使用情况的代码。这个类的代码是用纯Java编写的。

import java.io.IOException;
import java.io.RandomAccessFile;

/**
 * Utilities available only on Linux Operating System.
 * 
 * <p>
 * A typical use is to assign a thread to CPU monitoring:
 * </p>
 * 
 * <pre>
 * &#064;Override
 * public void run() {
 *  while (CpuUtil.monitorCpu) {
 * 
 *      LinuxUtils linuxUtils = new LinuxUtils();
 * 
 *      int pid = android.os.Process.myPid();
 *      String cpuStat1 = linuxUtils.readSystemStat();
 *      String pidStat1 = linuxUtils.readProcessStat(pid);
 * 
 *      try {
 *          Thread.sleep(CPU_WINDOW);
 *      } catch (Exception e) {
 *      }
 * 
 *      String cpuStat2 = linuxUtils.readSystemStat();
 *      String pidStat2 = linuxUtils.readProcessStat(pid);
 * 
 *      float cpu = linuxUtils.getSystemCpuUsage(cpuStat1, cpuStat2);
 *      if (cpu &gt;= 0.0f) {
 *          _printLine(mOutput, &quot;total&quot;, Float.toString(cpu));
 *      }
 * 
 *      String[] toks = cpuStat1.split(&quot; &quot;);
 *      long cpu1 = linuxUtils.getSystemUptime(toks);
 * 
 *      toks = cpuStat2.split(&quot; &quot;);
 *      long cpu2 = linuxUtils.getSystemUptime(toks);
 * 
 *      cpu = linuxUtils.getProcessCpuUsage(pidStat1, pidStat2, cpu2 - cpu1);
 *      if (cpu &gt;= 0.0f) {
 *          _printLine(mOutput, &quot;&quot; + pid, Float.toString(cpu));
 *      }
 * 
 *      try {
 *          synchronized (this) {
 *              wait(CPU_REFRESH_RATE);
 *          }
 *      } catch (InterruptedException e) {
 *          e.printStackTrace();
 *          return;
 *      }
 *  }
 * 
 *  Log.i(&quot;THREAD CPU&quot;, &quot;Finishing&quot;);
 * }
 * </pre>
 */
public final class LinuxUtils {

    // Warning: there appears to be an issue with the column index with android linux:
    // it was observed that on most present devices there are actually
    // two spaces between the 'cpu' of the first column and the value of 
    // the next column with data. The thing is the index of the idle 
    // column should have been 4 and the first column with data should have index 1. 
    // The indexes defined below are coping with the double space situation.
    // If your file contains only one space then use index 1 and 4 instead of 2 and 5.
    // A better way to deal with this problem may be to use a split method 
    // not preserving blanks or compute an offset and add it to the indexes 1 and 4.

    private static final int FIRST_SYS_CPU_COLUMN_INDEX = 2;

    private static final int IDLE_SYS_CPU_COLUMN_INDEX = 5;

    /** Return the first line of /proc/stat or null if failed. */
    public String readSystemStat() {

        RandomAccessFile reader = null;
        String load = null;

        try {
            reader = new RandomAccessFile("/proc/stat", "r");
            load = reader.readLine();
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            Streams.close(reader);
        }

        return load;
    }

    /**
     * Compute and return the total CPU usage, in percent.
     * 
     * @param start
     *            first content of /proc/stat. Not null.
     * @param end
     *            second content of /proc/stat. Not null.
     * @return 12.7 for a CPU usage of 12.7% or -1 if the value is not
     *         available.
     * @see {@link #readSystemStat()}
     */
    public float getSystemCpuUsage(String start, String end) {
        String[] stat = start.split("\\s");
        long idle1 = getSystemIdleTime(stat);
        long up1 = getSystemUptime(stat);

        stat = end.split("\\s");
        long idle2 = getSystemIdleTime(stat);
        long up2 = getSystemUptime(stat);

        // don't know how it is possible but we should care about zero and
        // negative values.
        float cpu = -1f;
        if (idle1 >= 0 && up1 >= 0 && idle2 >= 0 && up2 >= 0) {
            if ((up2 + idle2) > (up1 + idle1) && up2 >= up1) {
                cpu = (up2 - up1) / (float) ((up2 + idle2) - (up1 + idle1));
                cpu *= 100.0f;
            }
        }

        return cpu;
    }

    /**
     * Return the sum of uptimes read from /proc/stat.
     * 
     * @param stat
     *            see {@link #readSystemStat()}
     */
    public long getSystemUptime(String[] stat) {
        /*
         * (from man/5/proc) /proc/stat kernel/system statistics. Varies with
         * architecture. Common entries include: cpu 3357 0 4313 1362393
         * 
         * The amount of time, measured in units of USER_HZ (1/100ths of a
         * second on most architectures, use sysconf(_SC_CLK_TCK) to obtain the
         * right value), that the system spent in user mode, user mode with low
         * priority (nice), system mode, and the idle task, respectively. The
         * last value should be USER_HZ times the second entry in the uptime
         * pseudo-file.
         * 
         * In Linux 2.6 this line includes three additional columns: iowait -
         * time waiting for I/O to complete (since 2.5.41); irq - time servicing
         * interrupts (since 2.6.0-test4); softirq - time servicing softirqs
         * (since 2.6.0-test4).
         * 
         * Since Linux 2.6.11, there is an eighth column, steal - stolen time,
         * which is the time spent in other operating systems when running in a
         * virtualized environment
         * 
         * Since Linux 2.6.24, there is a ninth column, guest, which is the time
         * spent running a virtual CPU for guest operating systems under the
         * control of the Linux kernel.
         */

        // with the following algorithm, we should cope with all versions and
        // probably new ones.
        long l = 0L;

        for (int i = FIRST_SYS_CPU_COLUMN_INDEX; i < stat.length; i++) {
            if (i != IDLE_SYS_CPU_COLUMN_INDEX ) { // bypass any idle mode. There is currently only one.
                try {
                    l += Long.parseLong(stat[i]);
                } catch (NumberFormatException ex) {
                    ex.printStackTrace();
                    return -1L;
                }
            }
        }

        return l;
    }

    /**
     * Return the sum of idle times read from /proc/stat.
     * 
     * @param stat
     *            see {@link #readSystemStat()}
     */
    public long getSystemIdleTime(String[] stat) {
        try {
            return Long.parseLong(stat[IDLE_SYS_CPU_COLUMN_INDEX]);
        } catch (NumberFormatException ex) {
            ex.printStackTrace();
        }

        return -1L;
    }

    /** Return the first line of /proc/pid/stat or null if failed. */
    public String readProcessStat(int pid) {

        RandomAccessFile reader = null;
        String line = null;

        try {
            reader = new RandomAccessFile("/proc/" + pid + "/stat", "r");
            line = reader.readLine();
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            Streams.close(reader);
        }

        return line;
    }

    /**
     * Compute and return the CPU usage for a process, in percent.
     * 
     * <p>
     * The parameters {@code totalCpuTime} is to be the one for the same period
     * of time delimited by {@code statStart} and {@code statEnd}.
     * </p>
     * 
     * @param start
     *            first content of /proc/pid/stat. Not null.
     * @param end
     *            second content of /proc/pid/stat. Not null.
     * @return the CPU use in percent or -1f if the stats are inverted or on
     *         error
     * @param uptime
     *            sum of user and kernel times for the entire system for the
     *            same period of time.
     * @return 12.7 for a cpu usage of 12.7% or -1 if the value is not available
     *         or an error occurred.
     * @see {@link #readProcessStat(int)}
     */
    public float getProcessCpuUsage(String start, String end, long uptime) {

        String[] stat = start.split("\\s");
        long up1 = getProcessUptime(stat);

        stat = end.split("\\s");
        long up2 = getProcessUptime(stat);

        float ret = -1f;
        if (up1 >= 0 && up2 >= up1 && uptime > 0.) {
            ret = 100.f * (up2 - up1) / (float) uptime;
        }

        return ret;
    }

    /**
     * Decode the fields of the file {@code /proc/pid/stat} and return (utime +
     * stime)
     * 
     * @param stat
     *            obtained with {@link #readProcessStat(int)}
     */
    public long getProcessUptime(String[] stat) {
        return Long.parseLong(stat[14]) + Long.parseLong(stat[15]);
    }

    /**
     * Decode the fields of the file {@code /proc/pid/stat} and return (cutime +
     * cstime)
     * 
     * @param stat
     *            obtained with {@link #readProcessStat(int)}
     */
    public long getProcessIdleTime(String[] stat) {
        return Long.parseLong(stat[16]) + Long.parseLong(stat[17]);
    }

    /**
     * Return the total CPU usage, in percent.
     * <p>
     * The call is blocking for the time specified by elapse.
     * </p>
     * 
     * @param elapse
     *            the time in milliseconds between reads.
     * @return 12.7 for a CPU usage of 12.7% or -1 if the value is not
     *         available.
     */
    public float syncGetSystemCpuUsage(long elapse) {

        String stat1 = readSystemStat();
        if (stat1 == null) {
            return -1.f;
        }

        try {
            Thread.sleep(elapse);
        } catch (Exception e) {
        }

        String stat2 = readSystemStat();
        if (stat2 == null) {
            return -1.f;
        }

        return getSystemCpuUsage(stat1, stat2);
    }

    /**
     * Return the CPU usage of a process, in percent.
     * <p>
     * The call is blocking for the time specified by elapse.
     * </p>
     * 
     * @param pid
     * @param elapse
     *            the time in milliseconds between reads.
     * @return 6.32 for a CPU usage of 6.32% or -1 if the value is not
     *         available.
     */
    public float syncGetProcessCpuUsage(int pid, long elapse) {

        String pidStat1 = readProcessStat(pid);
        String totalStat1 = readSystemStat();
        if (pidStat1 == null || totalStat1 == null) {
            return -1.f;
        }

        try {
            Thread.sleep(elapse);
        } catch (Exception e) {
            e.printStackTrace();
            return -1.f;
        }

        String pidStat2 = readProcessStat(pid);
        String totalStat2 = readSystemStat();
        if (pidStat2 == null || totalStat2 == null) {
            return -1.f;
        }

        String[] toks = totalStat1.split("\\s");
        long cpu1 = getSystemUptime(toks);

        toks = totalStat2.split("\\s");
        long cpu2 = getSystemUptime(toks);

        return getProcessCpuUsage(pidStat1, pidStat2, cpu2 - cpu1);
    }

}

有几种方法可以利用这个类。您可以调用syncGetSystemCpuUsagesyncGetProcessCpuUsage,但每个都阻塞调用线程。由于一个常见的问题是同时监控总 CPU 使用率和当前进程的 CPU 使用率,因此我设计了一个计算它们的类。该类包含一个专用线程。输出管理是特定于实现的,您需要自己编写代码。

可以通过几种方式自定义该类。常量CPU_WINDOW 定义了读取的深度,即读取和计算相应 CPU 负载之间的毫秒数。 CPU_REFRESH_RATE 是每次 CPU 负载测量之间的时间。不要将CPU_REFRESH_RATE 设置为 0,因为它会在第一次读取后挂起线程。

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;

import android.app.Application;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;

import my.app.LinuxUtils;
import my.app.Streams;
import my.app.TestReport;
import my.app.Utils;

public final class CpuUtil {

    private static final int CPU_WINDOW = 1000;

    private static final int CPU_REFRESH_RATE = 100; // Warning: anything but > 0

    private static HandlerThread handlerThread;

    private static TestReport output;

    static {
        output = new TestReport();
        output.setDateFormat(Utils.getDateFormat(Utils.DATE_FORMAT_ENGLISH));
    }

    private static boolean monitorCpu;

    /**
     * Construct the class singleton. This method should be called in
     * {@link Application#onCreate()}
     * 
     * @param dir
     *            the parent directory
     * @param append
     *            mode
     */
    public static void setOutput(File dir, boolean append) {
        try {
            File file = new File(dir, "cpu.txt");
            output.setOutputStream(new FileOutputStream(file, append));
            if (!append) {
                output.println(file.getAbsolutePath());
                output.newLine(1);

                // print header
                _printLine(output, "Process", "CPU%");

                output.flush();
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    /** Start CPU monitoring */
    public static boolean startCpuMonitoring() {
        CpuUtil.monitorCpu = true;

        handlerThread = new HandlerThread("CPU monitoring"); //$NON-NLS-1$
        handlerThread.start();

        Handler handler = new Handler(handlerThread.getLooper());
        handler.post(new Runnable() {

            @Override
            public void run() {
                while (CpuUtil.monitorCpu) {

                    LinuxUtils linuxUtils = new LinuxUtils();

                    int pid = android.os.Process.myPid();
                    String cpuStat1 = linuxUtils.readSystemStat();
                    String pidStat1 = linuxUtils.readProcessStat(pid);

                    try {
                        Thread.sleep(CPU_WINDOW);
                    } catch (Exception e) {
                    }

                    String cpuStat2 = linuxUtils.readSystemStat();
                    String pidStat2 = linuxUtils.readProcessStat(pid);

                    float cpu = linuxUtils
                            .getSystemCpuUsage(cpuStat1, cpuStat2);
                    if (cpu >= 0.0f) {
                        _printLine(output, "total", Float.toString(cpu));
                    }

                    String[] toks = cpuStat1.split(" ");
                    long cpu1 = linuxUtils.getSystemUptime(toks);

                    toks = cpuStat2.split(" ");
                    long cpu2 = linuxUtils.getSystemUptime(toks);

                    cpu = linuxUtils.getProcessCpuUsage(pidStat1, pidStat2,
                            cpu2 - cpu1);
                    if (cpu >= 0.0f) {
                        _printLine(output, "" + pid, Float.toString(cpu));
                    }

                    try {
                        synchronized (this) {
                            wait(CPU_REFRESH_RATE);
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        return;
                    }
                }

                Log.i("THREAD CPU", "Finishing");
            }

        });

        return CpuUtil.monitorCpu;
    }

    /** Stop CPU monitoring */
    public static void stopCpuMonitoring() {
        if (handlerThread != null) {
            monitorCpu = false;
            handlerThread.quit();
            handlerThread = null;
        }
    }

    /** Dispose of the object and release the resources allocated for it */
    public void dispose() {

        monitorCpu = false;

        if (output != null) {
            OutputStream os = output.getOutputStream();
            if (os != null) {
                Streams.close(os);
                output.setOutputStream(null);
            }

            output = null;
        }
    }

    private static void _printLine(TestReport output, String process, String cpu) {
        output.stampln(process + ";" + cpu);
    }

}

【讨论】:

  • 这似乎是一个有趣的代码。但是,我想找出每个实验运行时的平均 CPU 和平均内存消耗。可以给点建议吗
【解决方案4】:

由于 OP 询问了 CPU 使用情况和内存使用情况(接受的答案仅显示获取 cpu 使用情况的技术),我想推荐 ActivityManager 类,特别是这个问题的接受答案:How to get current memory usage in android?

【讨论】:

    【解决方案5】:

    检查Debug 类。 http://developer.android.com/reference/android/os/Debug.htmlDebug.getNativeHeapAllocatedSize()

    它具有获取使用的本机堆的方法,即由应用程序中的外部位图使用。 对于应用内部使用的堆,您可以在 Android SDK 附带的 DDMS 工具中看到,也可以通过 Eclipse 获得。

    本机堆 + DDMS 中指示的堆构成了您的应用正在分配的总堆。

    对于 CPU 使用率,我不确定是否可以通过 API/SDK 提供任何东西。

    【讨论】:

    • Hey Mathias..感谢您的输入,但我发现代码运行良好。我在外面,所以无法回应你。顺便说一句,现在我正在研究内存使用点。我会在一两天内发布它的代码。
    • 嗨 Mathias.. 我想通过我的应用程序代码找到移动设备中的当前内存使用情况,因此 DDMS 在这种情况下无法提供帮助。所以我所做的是我使用了 /proc/meminfo 命令并解析了响应。但它显示的可用内存非常少。所以我只是对回应感到困惑。请在这里查看我的查询stackoverflow.com/questions/3170691/…
    • @MathiasLin 您的方法仅适用于 DDMS。如何在运行时在应用程序内部获取这些信息?
    【解决方案6】:

    进入android终端,然后你可以输入以下命令:dumpsys cpuinfo

    shell@android:/ $ dumpsys cpuinfo                                              
    Load: 0.8 / 0.75 / 1.15
    CPU usage from 69286ms to 9283ms ago with 99% awake:
      47% 1118/com.wxg.sodproject: 12% user + 35% kernel
      1.6% 1225/android.process.media: 1% user + 0.6% kernel
      1.3% 263/mpdecision: 0.1% user + 1.2% kernel
      0.1% 32747/kworker/u:1: 0% user + 0.1% kernel
      0.1% 883/com.android.systemui: 0.1% user + 0% kernel
      0.1% 521/system_server: 0.1% user + 0% kernel / faults: 14 minor
      0.1% 1826/com.quicinc.trepn: 0.1% user + 0% kernel
      0.1% 2462/kworker/0:2: 0.1% user + 0% kernel
      0.1% 32649/kworker/0:0: 0% user + 0.1% kernel
      0% 118/mmcqd/0: 0% user + 0% kernel
      0% 179/surfaceflinger: 0% user + 0% kernel
      0% 46/kinteractiveup: 0% user + 0% kernel
      0% 141/jbd2/mmcblk0p26: 0% user + 0% kernel
      0% 239/sdcard: 0% user + 0% kernel
      0% 1171/com.xiaomi.channel:pushservice: 0% user + 0% kernel / faults: 1 minor
      0% 1207/com.xiaomi.channel: 0% user + 0% kernel / faults: 1 minor
      0% 32705/kworker/0:1: 0% user + 0% kernel
    12% TOTAL: 3.2% user + 9.4% kernel + 0% iowait
    

    【讨论】:

    • 提问者正在寻找 API(应用程序编程接口)来获取此信息。
    • 只能由系统应用调用,所以不适合在Android应用内调用。
    猜你喜欢
    • 2011-03-11
    • 1970-01-01
    • 2012-06-11
    • 1970-01-01
    • 1970-01-01
    • 2013-04-25
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多