• Android Framework 常见解决方案(22)防应用被LowMemoryKillerDaemon(LMKD)杀掉


    1 原理说明

    LMKD 借助 Linux 内核的 OOM(Out of Memory)机制来管理内存。当系统内存不足时,OOM 触发器会发送信号给LMKD,通知其进行内存管理。LMKD根据预先定义的策略和优先级,选择性地终止一些进程,以释放内存。

    LMKD运行流程如下:

    1. 监测内存使用:LMKD 定期检查系统内存使用情况,包括各个进程的内存占用和系统总体内存压力。
    2. 内存压力评估:根据内存使用情况,LMKD 会计算出当前的内存压力指数,以判断是否需要进行内存管理。
    3. 内存压力事件处理:当内存压力指数超过一定阈值时,LMKD 触发内存压力事件,并根据预先配置的策略进行相应的处理。
    4. 进程终止:LMKD 根据策略和优先级,选择性地终止一些进程。通常,LMKD 会优先终止那些占用内存较多、优先级较低或者处于后台运行的进程。
    5. 释放内存:通过终止进程释放的内存会被回收,从而使系统内存得到释放,缓解内存压力。
    6. 日志记录和统计:LMKD 记录终止的进程信息和释放的内存量,并将其记录到系统日志中,以供后续分析和优化。

    这里选择运行到第4步时进行进程终止过滤,即使用包名进行过滤。

    2 修改方案(Android R S)

    修改文件为:AOSP/system/memory/lmkd/lmkd.cpp,不同可能lmkd.cpp的位置不同,本质上都是修改kill_one_process的实现,过滤掉包名,具体代码修改如下:

    1. static int kill_one_process(struct proc* procp, int min_oom_score, struct kill_info *ki,
    2. union meminfo *mi, struct wakeup_info *wi, struct timespec *tm,
    3. struct psi_data *pd) {
    4. int pid = procp->pid;
    5. int pidfd = procp->pidfd;
    6. uid_t uid = procp->uid;
    7. char *taskname;
    8. int r;
    9. int result = -1;
    10. struct memory_stat *mem_st;
    11. struct kill_stat kill_st;
    12. int64_t tgid;
    13. int64_t rss_kb;
    14. int64_t swap_kb;
    15. static char buf[PAGE_SIZE];
    16. + //AGS add start
    17. + char packageName[128] = {""};
    18. + //AGS add end
    19. if (!read_proc_status(pid, buf, sizeof(buf))) {
    20. goto out;
    21. }
    22. if (!parse_status_tag(buf, PROC_STATUS_TGID_FIELD, &tgid)) {
    23. ALOGE("Unable to parse tgid from /proc/%d/status", pid);
    24. goto out;
    25. }
    26. if (tgid != pid) {
    27. ALOGE("Possible pid reuse detected (pid %d, tgid %" PRId64 ")!", pid, tgid);
    28. goto out;
    29. }
    30. // Zombie processes will not have RSS / Swap fields.
    31. if (!parse_status_tag(buf, PROC_STATUS_RSS_FIELD, &rss_kb)) {
    32. goto out;
    33. }
    34. if (!parse_status_tag(buf, PROC_STATUS_SWAP_FIELD, &swap_kb)) {
    35. goto out;
    36. }
    37. taskname = proc_get_name(pid, buf, sizeof(buf));
    38. // taskname will point inside buf, do not reuse buf onwards.
    39. if (!taskname) {
    40. goto out;
    41. }
    42. + // AGS add start,添加包名过滤
    43. + strncpy(packageName, taskname,128);
    44. + //ALOGE("AGS-lmkd:packageName=%s,taskname=%s,strcmp=%d",packageName,taskname,strcmp(packageName,"com.xxx.xxx"));
    45. + if(!strncmp(packageName,"com.xxx.xxx",strlen("com.xxx.xxx")))
    46. + {
    47. + ALOGE("AGS add lmkd-whitelist:pkgname=%s",packageName);
    48. + return -1000;
    49. + }
    50. + //AGS add end
    51. mem_st = stats_read_memory_stat(per_app_memcg, pid, uid, rss_kb * 1024, swap_kb * 1024);
    52. //...
    53. out:
    54. /*
    55. * WARNING: After pid_remove() procp is freed and can't be used!
    56. * Therefore placed at the end of the function.
    57. */
    58. pid_remove(pid);
    59. return result;
    60. }

    思考与扩展:这里实际上也可以根据自己的需要做成白名单和黑名单来解决该问题,但是其本质都是包名的过滤。

  • 相关阅读:
    高级架构师_Elasticsearch_第二章kibana+IK分词器安装+索引操作+ 映射操作
    2-7:Http响应头知识点
    ZZNUOJ_C语言1114:逆序(完整代码)
    Abbkine脂质过氧化(丙二醛)含量检测试剂盒说明书
    爱做梦的人工智能「Stabled Diffusion」
    数据结构与算法课后题-第二章(顺序表)
    SpringCloud Alibaba Sentinel实现熔断与限流
    【Linux】Linux网络连接方式 + 虚拟机克隆、迁移与删除+虚拟机快照+Linux(CentOS)安装wmtools
    【RabbitMQ】初识消息队列 MQ,基于 Docker 部署 RabbitMQ,探索 RabbitMQ 基本使用,了解常见的消息类型
    【python】bin/dec/hex/bnr进制转换函数及fp32转十六进制
  • 原文地址:https://blog.csdn.net/vviccc/article/details/133386184