绘制Android设备内存变化图

一、内存使用占比计算

内存使用占比(Memory Usage Percentage)可以通过不同的方式计算,具体取决于您想要衡量的是哪种类型的内存使用情况。以下是几种常见的计算方法:

  1. 基于MemTotal和MemFree

    • 公式 : <math xmlns="http://www.w3.org/1998/Math/MathML"> Memory Usage Percentage = ( 1 − MemFree MemTotal ) × 100 % \text{Memory Usage Percentage} = \left(1 - \frac{\text{MemFree}}{\text{MemTotal}}\right) \times 100\% </math>Memory Usage Percentage=(1−MemTotalMemFree)×100%
    • 说明 :此公式仅考虑了空闲内存(MemFree),没有考虑到缓存或缓冲区等其他因素。
  2. 基于MemTotal和MemAvailable

    • 公式 : <math xmlns="http://www.w3.org/1998/Math/MathML"> Memory Usage Percentage = ( 1 − MemAvailable MemTotal ) × 100 % \text{Memory Usage Percentage} = \left(1 - \frac{\text{MemAvailable}}{\text{MemTotal}}\right) \times 100\% </math>Memory Usage Percentage=(1−MemTotalMemAvailable)×100%
    • 说明 :此公式考虑了系统可以使用的总内存(MemAvailable),包括空闲内存以及可立即释放的缓存和缓冲区。
  3. 基于MemTotal和实际使用的内存

    • 公式 : <math xmlns="http://www.w3.org/1998/Math/MathML"> Memory Usage Percentage = ( MemTotal − ( MemFree + Buffers + Cached ) MemTotal ) × 100 % \text{Memory Usage Percentage} = \left(\frac{\text{MemTotal} - (\text{MemFree} + \text{Buffers} + \text{Cached})}{\text{MemTotal}}\right) \times 100\% </math>Memory Usage Percentage=(MemTotalMemTotal−(MemFree+Buffers+Cached))×100%
    • 说明 :此公式考虑了空闲内存(MemFree)、缓存(Cached)和缓冲区(Buffers),这些通常不计入实际使用的内存。

在Linux系统中,通常推荐使用基于MemAvailable的计算方法,因为它提供了更接近实际可用内存的值。这种方法考虑到了操作系统缓存和缓冲区对可用内存的影响,而这些缓存和缓冲区在需要时可以被迅速释放给应用程序使用。

下面是一个具体的例子,假设我们有以下内存统计数据:

  • MemTotal: 16GB (16384 MB)
  • MemFree: 2GB (2048 MB)
  • MemAvailable: 4GB (4096 MB)
  • Buffers: 1GB (1024 MB)
  • Cached: 2GB (2048 MB)

使用基于MemAvailable的方法计算内存使用占比:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> Memory Usage Percentage = ( 1 − 4096 16384 ) × 100 % = ( 1 − 1 4 ) × 100 % = 75 % \text{Memory Usage Percentage} = \left(1 - \frac{4096}{16384}\right) \times 100\% = \left(1 - \frac{1}{4}\right) \times 100\% = 75\% </math>Memory Usage Percentage=(1−163844096)×100%=(1−41)×100%=75%

因此,内存使用占比为75%。

二、实时内存占比

实时展示内存信息脚本:

show_mem.py

python 复制代码
import subprocess
import time
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

def ensure_root():
    try:
        subprocess.run(["adb", "root"], check=True)
        print("Root permission granted.")
    except subprocess.CalledProcessError as e:
        print("Failed to get root permission, the script may not work correctly:", e)

def get_memory_info():
    try:
        cmd = "adb shell cat /proc/meminfo"
        result = subprocess.run(cmd, shell=True, text=True, capture_output=True)
        meminfo = result.stdout.splitlines()
        
        mem_total = int(next(line for line in meminfo if line.startswith('MemTotal:')).split()[1])
        mem_free = int(next(line for line in meminfo if line.startswith('MemFree:')).split()[1])
        buffers = int(next(line for line in meminfo if line.startswith('Buffers:')).split()[1])
        cached = int(next(line for line in meminfo if line.startswith('Cached:')).split()[1])

        mem_used = mem_total - (mem_free + buffers + cached)
        mem_usage_percent = (mem_used / mem_total) * 100

        return mem_usage_percent
    except Exception as e:
        print("Error retrieving memory info:", e)
        return None

# 初始化图表
fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = plt.plot(xdata, ydata, 'r-')

# 初始化文本标签
txt_mem_usage = ax.text(0.5, 0.9, '', transform=ax.transAxes, ha='center')

def init():
    ax.set_xlim(0, 60)  # 初始化x轴显示60秒数据
    ax.set_ylim(0, 100)  # 内存使用率在0%到100%之间
    ax.set_xlabel('Time (seconds)')
    ax.set_ylabel('Memory Usage (%)')
    ax.set_title('Memory Usage - Real-time')
    return ln,

def update(frame):
    mem_usage = get_memory_info()
    if mem_usage is not None:
        xdata.append(frame)
        ydata.append(mem_usage)
        
        # 更新图表数据
        ln.set_data(xdata, ydata)
        txt_mem_usage.set_text(f'Memory Usage: {mem_usage:.2f}%')
        
        # 动态更新x轴范围,始终显示最近的60秒数据
        ax.set_xlim(max(xdata[0] - 1, frame - 60), frame + 1)
        
        # 重新绘制图表
        fig.canvas.draw()
    else:
        txt_mem_usage.set_text('Failed to retrieve memory information')

    return ln, txt_mem_usage,

ensure_root()  # 在脚本开始的地方调用确保root权限的函数

# 创建动画
ani = FuncAnimation(fig, update, frames=range(1000),
                    init_func=init, blit=True, interval=1000)

plt.show()

三、历史内存占比

保存内存信息可执行文件代码:

mem_collect.c

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#define MEMINFO_PATH "/proc/meminfo"
#define OUTPUT_FILE "/data/memory_info.txt"
#define SLEEP_TIME 5 // 每秒执行一次

// 定义要保存的字段
const char* fields_to_save[] = {
    "MemTotal",
    "MemFree",
    "MemAvailable",
    "Buffers",
    "Cached"
};
const size_t fields_count = sizeof(fields_to_save) / sizeof(fields_to_save[0]);

void save_memory_info_with_timestamp() {
    FILE *fp = fopen(OUTPUT_FILE, "a"); // 追加模式打开文件
    if (fp == NULL) {
        perror("Error opening output file");
        return;
    }

    FILE *meminfo_file = fopen(MEMINFO_PATH, "r");
    if (meminfo_file == NULL) {
        perror("Error opening meminfo file");
        fclose(fp);
        return;
    }

    char buffer[1024];
    char *line, *field;
    float value;
    time_t now = time(NULL);
    struct tm *local_time = localtime(&now);

    // 格式化时间戳
    fprintf(fp, "Time: %d-%02d-%02d %02d:%02d:%02d -\t",
            local_time->tm_year + 1900, local_time->tm_mon + 1, local_time->tm_mday,
            local_time->tm_hour, local_time->tm_min, local_time->tm_sec);

    for (size_t i = 0; i < fields_count; ++i) {
        rewind(meminfo_file); // 重置文件指针到文件开头
        while (fgets(buffer, sizeof(buffer), meminfo_file)) {
            if (strstr(buffer, fields_to_save[i])) {
                field = strtok(buffer, ":");
                field = strtok(NULL, ":"); // 跳过字段名,获取数值
                value = atof(field);
                fprintf(fp, "%s: %f kB\t", fields_to_save[i], value);
                break;
            }
        }
    }

    fprintf(fp, "\n"); // 每个时间戳后添加一个空行

    fclose(meminfo_file);
    fclose(fp);
}

int main() {
	system("rm -rf /data/memory_info.txt"); 
    while (1) {
        save_memory_info_with_timestamp();
        sleep(SLEEP_TIME);
    }
    return 0;
}
  • 将mem_collect.c放在Android源码环境下编译,或者配置Android ndk交叉编译环境
  • 编译完成后将可执行文件push到机器中/system/bin/下(push前adb root && adb remount)
  • 执行mem_collect保存机器内存信息,保存文件路径:/data/memory_info.txt

解析memory_info.txt脚本:

mem_parser.py

python 复制代码
import matplotlib.pyplot as plt
import datetime

# 定义一个函数来解析每一行的数据
def parse_line(line):
    parts = line.strip().split()
    timestamp_str = parts[1] + ' ' + parts[2]
    mem_info = {}
    
    for i, part in enumerate(parts):
        if part.endswith(':'):
            key = part[:-1]  # 去掉冒号
            if key in ['MemTotal', 'MemFree', 'MemAvailable', 'Buffers', 'Cached']:
                value = float(parts[i+1].replace('kB', ''))  # 去掉'kB'后缀
                mem_info[key] = value
    
    # 计算内存使用百分比
    if 'MemTotal' in mem_info and 'MemAvailable' in mem_info:
        mem_used_percent = (mem_info['MemTotal'] - mem_info['MemAvailable']) / mem_info['MemTotal'] * 100
    else:
        raise ValueError("Could not find total or available memory values.")
    
    return timestamp_str, mem_used_percent

# 读取文件并解析每一行数据
timestamps = []
mem_used_percentages = []

with open('D:\python\memory_info.txt', 'r') as file:
    for line in file:
        if line.startswith('Time:'):
            timestamp, mem_used_percent = parse_line(line)
            timestamps.append(datetime.datetime.strptime(timestamp, '%Y-%m-%d %H:%M:%S'))
            mem_used_percentages.append(mem_used_percent)

# 绘制图表
plt.figure(figsize=(10, 5))
plt.ylim(0, 100)
plt.plot(timestamps, mem_used_percentages, marker='o')
plt.title('Memory Usage Over Time')
plt.xlabel('Timestamp')
plt.ylabel('Memory Used (%)')
plt.grid(True)
plt.xticks(rotation=45)
plt.tight_layout()  # 自动调整子图参数,使之填充整个图像区域
plt.show()

运行环境: Ubuntu 20.04.6 LTS、 Windows 10、 Python 3.11.3

相关推荐
小蜜蜂嗡嗡1 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi001 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体
zhangphil3 小时前
Android理解onTrimMemory中ComponentCallbacks2的内存警戒水位线值
android
你过来啊你3 小时前
Android View的绘制原理详解
android
移动开发者1号6 小时前
使用 Android App Bundle 极致压缩应用体积
android·kotlin
移动开发者1号6 小时前
构建高可用线上性能监控体系:从原理到实战
android·kotlin
ii_best11 小时前
按键精灵支持安卓14、15系统,兼容64位环境开发辅助工具
android
美狐美颜sdk11 小时前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
恋猫de小郭16 小时前
Meta 宣布加入 Kotlin 基金会,将为 Kotlin 和 Android 生态提供全新支持
android·开发语言·ios·kotlin
aqi0016 小时前
FFmpeg开发笔记(七十七)Android的开源音视频剪辑框架RxFFmpeg
android·ffmpeg·音视频·流媒体