绘制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

相关推荐
落落落sss20 分钟前
sharding-jdbc分库分表
android·java·开发语言·数据库·servlet·oracle
消失的旧时光-19433 小时前
kotlin的密封类
android·开发语言·kotlin
服装学院的IT男4 小时前
【Android 13源码分析】WindowContainer窗口层级-4-Layer树
android
CCTV果冻爽5 小时前
Android 源码集成可卸载 APP
android
码农明明5 小时前
Android源码分析:从源头分析View事件的传递
android·操作系统·源码阅读
秋月霜风6 小时前
mariadb主从配置步骤
android·adb·mariadb
Python私教7 小时前
Python ORM 框架 SQLModel 快速入门教程
android·java·python
编程乐学8 小时前
基于Android Studio 蜜雪冰城(奶茶饮品点餐)—原创
android·gitee·android studio·大作业·安卓课设·奶茶点餐
problc9 小时前
Android中的引用类型:Weak Reference, Soft Reference, Phantom Reference 和 WeakHashMap
android
IH_LZH9 小时前
Broadcast:Android中实现组件及进程间通信
android·java·android studio·broadcast