当前位置: 首页 > article >正文

lmk内存压力测试工具mem-pressure源码剖析

背景:

android系统开发过程中,经常会遇到一些low memory kill的问题,在分析这些系统低内存导致被杀问题时候,经常因为不好复现而成为一个比较烦恼的阻碍。因为这种低内存问题本身就不属于一种功能操作类型的问题,属于一种系统当前可使用的内存少导致的问题,所以分析这类lmk低内存被杀的情况迫切需要一种可以帮助我们复现系统低内存的工具,今天马哥就给大家介绍一个内存压力工具mem-pressure详细使用和源码剖析。

mem-pressure工具实战展示

系统的mem-pressure并不是自带集成的,需要集成这个mem-pressure工具是需要自己进行额外编译的,所以要先进行编译mem-pressure的bin文件后再使用。
编译mem-pressure

test@test:~/aosp15$ make mem-pressure
============================================
PLATFORM_VERSION_CODENAME=VanillaIceCream
PLATFORM_VERSION=VanillaIceCream
TARGET_PRODUCT=sdk_phone64_x86_64
TARGET_BUILD_VARIANT=eng
TARGET_ARCH=x86_64
TARGET_ARCH_VARIANT=x86_64
TARGET_2ND_ARCH_VARIANT=x86_64
HOST_OS=linux
HOST_OS_EXTRA=Linux-5.15.0-130-generic-x86_64-Ubuntu-20.04.3-LTS
HOST_CROSS_OS=windows
BUILD_ID=AP3A.241005.015.A2
OUT_DIR=out
============================================
[100% 6/6 1s remaining] Install: out/target/product/emu64x/system/bin/mem-pressure

#### build completed successfully (6 seconds) ####

注意这里可以看到可以成功编译出mem-pressure

然后在push到手机设备上

test@test:~/aosp15$ adb push out/target/product/emu64x/system/bin/mem-pressure /data/local/tmp/
out/target/product/emu64x/system/bin/mem-pressure: 1 file pushed, 0 skipped. 82.2 MB/s (51264 bytes in 0.001s)

接下来既可以正常使用mem-pressure

130|emu64x:/data/local/tmp # ./mem-pressure -h                                                                                                                                                                    
Usage: [OPTIONS]

  -d N: Duration in microsecond to sleep between each allocation.
  -i N: Number of iterations to run the alloc process.
  -o N: The oom_score to set the child process to before alloc.
  -s N: Number of bytes to allocate in an alloc process loop.
Aborted 


可以看到mem-pressure可以设置一些参数
正常使用也可以不带任何的参数,都使用默认的:

emu64x:/data/local/tmp # ./mem-pressure                                                                                                                                                                           
Child 0 allocated 5936 MB
Child 1 allocated 5968 MB

可以到执行mem-pressure后有多个子进程在申请5936 MB内存,同时看看logcat是否有lowmemorykiller相关打印:

在这里插入图片描述

源码分析

源码路径:
system/extras/alloc-stress/mem-pressure.cpp
完整源码:
先看main方法

void usage() {
    printf("Usage: [OPTIONS]\n\n"
           "  -d N: Duration in microsecond to sleep between each allocation.\n"
           "  -i N: Number of iterations to run the alloc process.\n"
           "  -o N: The oom_score to set the child process to before alloc.\n"
           "  -s N: Number of bytes to allocate in an alloc process loop.\n");
}

int main(int argc, char* argv[]) {
    pid_t pid;
    size_t* shared;
    int c, i = 0;

    size_t duration = 1000;
    int iterations = 0;
    const char* oom_score = "899";
    size_t step_size = 2 * 1024 * 1024;  // 2 MB
    size_t size = step_size;

    while ((c = getopt(argc, argv, "hi:d:o:s:")) != -1) {
        switch (c) {
            case 'i':
                iterations = atoi(optarg);
                break;
            case 'd':
                duration = atoi(optarg);
                break;
            case 'o':
                oom_score = optarg;
                break;
            case 's':
                step_size = atoi(optarg);
                break;
            case 'h':
                usage();
                abort();
            default:
                abort();
        }
    }

    shared = (size_t*)mmap(NULL, sizeof(size_t), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED,
                           0, 0);

    while (iterations == 0 || i < iterations) {
        *shared = 0;
        pid = fork();//不断for新的子进程
        if (!pid) {
            /* Child */
            add_pressure(shared, size, step_size, duration, oom_score);//子进程开始添加内存压力,这个是核心方法
            /* Shoud not get here */
            exit(0);
        } else {
            wait(NULL);//主进程一直等待,等到子进程内存到达极限死了,才会进行往下执行
            printf("Child %d allocated %zd MB\n", i, *shared / 1024 / 1024);//打印出子进程已经申请了多少内存
            size = *shared / 2;
        }
        i++;
    }
}

可以总结一下mem-pressure核心如下:
1、不断创建新的子进程
2、每个子进程进行相关的内存申请
3、子进程内存达到极限被杀了后会打印出申请的内存值

再看具体是怎么给进程内存加压的

//申请指定内存大小并进行设置为0
void* alloc_set(size_t size) {
    void* addr = NULL;

    addr = malloc(size);
    if (!addr) {
        printf("Allocating %zd MB failed\n", size / 1024 / 1024);
    } else {
        memset(addr, 0, size);
    }
    return addr;
}

void add_pressure(size_t* shared, size_t size, size_t step_size, size_t duration,
                  const char* oom_score) {
    int fd, ret;

    fd = open("/proc/self/oom_score_adj", O_WRONLY);//给进程的oom_score_adj写入相关adj值的文件
    ret = write(fd, oom_score, strlen(oom_score));//写人对应的oom_score到上面文件
    if (ret < 0) {
        printf("Writing oom_score_adj failed with err %s\n", strerror(errno));
    }
    close(fd);

    if (alloc_set(size)) {
        *shared = size;
    }
//这里会一直申请内存
    while (alloc_set(step_size)) {
        size += step_size;
        *shared = size;
        usleep(duration);//这里会有个延时1000us
    }
}

更多framework技术干货,请关注下面“千里马学框架”


http://www.kler.cn/a/533413.html

相关文章:

  • 飞行汽车中的无刷外转子电机、人形机器人中的无框力矩电机技术解析与应用
  • Leetcode - 周赛434
  • Java 大视界 -- Java 大数据在智能医疗影像诊断中的应用(72)
  • 四川正熠法律咨询有限公司正规吗可信吗?
  • P7497 四方喝彩 Solution
  • 阿里云盘PC端打不开解决办法
  • 防御与保护——防火墙安全策略配置
  • JDK17主要特性
  • 大话特征工程:3.特征扩展
  • 【Linux】文件描述符
  • 牛客比赛贪心算法
  • OpenEuler学习笔记(十九):搭建云表格服务
  • Java 基于微信小程序的高校失物招领平台小程序(附源码,文档)
  • c++中priority_queue的应用及模拟实现
  • Git--使用教程
  • 19爬虫:使用playwright登录超级鹰
  • 2025春招,高级程序员回答数据库问题
  • Kubernetes | Rocky Linux 8.9 安装部署 kubernetes集群
  • 4.回归与聚类算法 4.1线性回归
  • 学前端框架之前,你需要先理解 MVC
  • 【llm对话系统】大模型 Llama 如何进行量化和推理
  • FPV光纤无人机军事战场技术详解
  • 图像分类与目标检测算法
  • 基于全志H616的智能家居
  • R语言速通
  • PyQt6/PySide6 的 QDialog 类