Android Lost RAM的统计方法

本文深入探讨了Linux系统中出现lowmom问题时,LostRAM异常增大的现象。通过分析ActivityManagerService源码,揭示了LostRAM计算原理及其与totalSwapPss的关系,为解决内存管理问题提供了线索。

最近遇到一个Lost RAM占用内存达到1,296,701K,Free RAM只有157,924K 出现lowmom问题:

  MemInfo:    43,292K slab,   114,292K shmem,    65,292K vm alloc,    12,324K page tables     5,568K kernel stack
               1,572K buffers,   269,472K cached,   188,532K mapped,    75,412K free
  ZRAM:         4K RAM,   520,908K swap total,   520,908K swap free
  Free RAM:   157,924K
  Used RAM:   591,439K
  Lost RAM: 1,296,701K

可以看到,出现lowmom问题是,Used RAM并不高,和正常的相差无几。

发现问题出现时,Lost RAM异常的大,在总RAM一定的情况下,Used RAM稳定的情况下,Free RAM和Lost RAM 存在此消彼长的现象。

所以这里我将Lost RAM 统计相关的源码进行分析。

Lost RAM 统计的源码:/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
        - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
        - memInfo.getKernelUsedSizeKb() - memInfo.getZramTotalSizeKb();

我们可以使用命令:adb shell "dumpsys meminfo |grep RAM "

查看正常设备设备RAM信息。

Total RAM: 2,049,328K (status moderate)
 Free RAM: 1,267,152K (   37,644K cached pss +   345,436K cached kernel +   884,072K free)
 Used RAM:   487,842K (  307,414K used pss +   180,428K kernel)
 Lost RAM:   294,330K
     ZRAM:         4K physical used for         0K in swap (  520,908K total swap)
   Tuning: 192 (large 512), oom   184,320K, restore limit    61,440K (high-end-gfx)

即:Lost RAM =2,049,328K-((37,644K+307,414K)-totalSwapPss)- 884,072K-345,436K-180,428K-4k =294,330K

也就是Lost RAM 统计信息中,除了totalSwapPss未在上述命令查询结果中直接显示外,其他信息直接可以使用命令查看到。

可以看到正常情况下:2049328-(37644+307414)-884072-345436-180428-4-294330= -totalSwapPss = 0.

可以看到,正常情况下totalSwapPss的值并不大。

继续看源码:

    final void dumpApplicationMemoryUsage(FileDescriptor fd,
            PrintWriter pw, String prefix, String[] args, boolean brief, PrintWriter categoryPw) {
        ...

        ArrayList<ProcessRecord> procs = collectProcesses(pw, opti, packages, args);
        ...
        long totalSwapPss = 0;
        ...
        Debug.MemoryInfo mi = null;
        for (int i = procs.size() - 1 ; i >= 0 ; i--) {
                ...
                final long myTotalSwapPss = mi.getTotalSwappedOutPss();

                synchronized (this) {
                    if (r.thread != null && oomAdj == r.getSetAdjWithServices()) {
                        // Record this for posterity if the process has been stable.
                        r.baseProcessTracker.addPss(myTotalPss, myTotalUss, true, r.pkgList);
                    }
                }

                if (!isCheckinRequest && mi != null) {
                    ...
                    totalSwapPss += myTotalSwapPss;// 所有进程swap占用空间总和
                    ...
                }
            }
        }
        ...
    }

totalSwapPss 是所有进程swap占用空间总和。再其他值都正常的情况下,Lost RAM和totalSwapPss成正比关系。

所以接下来,需要进一步取排查totalSwapPss究竟和哪个进程有关系?

排查思路:将totalSwapPss += myTotalSwapPss;// 所有进程swap占用空间总和 这一行前面打印进程号。

排查结果:totalSwapPss实际上为0,日志打印各进程的myTotalSwapPss,所以这个思路无法定位问题。所以有了下一篇:Lost RAM可能的原因

 

 

### 关于 mmap 和 lostram 的技术信息及问题解决方案 在 Linux 系统中,`mmap` 是一种内存映射机制,允许将文件或设备映射到进程的地址空间[^1]。这使得文件操作可以像访问内存一样进行,从而提高性能和效率。然而,在使用 `mmap` 时可能会遇到一些错误,例如无效模块格式、内存分配失败等问题。 #### mmap 常见错误及其解决方案 1. **模块格式错误** 当尝试插入内核模块时,可能会出现类似以下的错误: ```bash insmod: error inserting 'poet_atkm.ko': -1 Invalid module format ``` 这通常是因为编译内核模块时使用的内核源代码版本与运行中的内核版本不匹配[^1]。为了解决此问题,请确保: - 使用与当前运行内核版本一致的内核源代码树。 - 在编译内核模块之前,执行 `make clean` 并重新编译模块。 2. **内存分配失败** 如果系统内存不足,`mmap` 调用可能会失败并返回 `-ENOMEM` 错误。这种情况下,可以通过以下方式解决: - 检查系统的可用内存,并释放不必要的资源。 - 调整系统的内存管理策略,例如增加交换空间。 #### lostram 技术背景 `lostram` 是指 Linux 内核中丢失的 RAM 页面(Lost RAM Pages)。这种情况可能由于内存去重(KSM,Kernel Samepage Merging)或其他内存管理机制导致。根据提供的引用[^2],`max_page_sharing` 参数用于限制虚拟内存 rmap 列表的增长,以避免其变得过大。这是因为 rmap 遍历的复杂度为 O(N),其中 N 是共享页面的 rmap_items 数量。 当 KSM 或其他内存管理功能导致页面丢失时,可以通过以下方法排查和解决问题: 1. **检查 KSM 配置** 确保 `max_page_sharing` 参数设置合理,以防止 rmap 列表过大。可以通过以下命令调整参数: ```bash echo 32 > /sys/kernel/mm/ksm/max_page_sharing ``` 2. **监控内存状态** 使用工具如 `vmstat` 或 `top` 监控内存使用情况,识别是否存在页面丢失问题。 3. **调试内核日志** 查看内核日志以获取更多信息,例如: ```bash dmesg | grep -i "lost ram" ``` #### 示例代码:mmap 使用示例 以下是一个简单的 `mmap` 使用示例,展示如何将文件映射到内存中: ```c #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <sys/stat.h> #include <unistd.h> int main() { int fd = open("example.txt", O_RDONLY); if (fd == -1) { perror("open"); return EXIT_FAILURE; } struct stat sb; if (fstat(fd, &sb) == -1) { perror("fstat"); close(fd); return EXIT_FAILURE; } void *addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (addr == MAP_FAILED) { perror("mmap"); close(fd); return EXIT_FAILURE; } printf("File content: %s\n", (char *)addr); munmap(addr, sb.st_size); close(fd); return EXIT_SUCCESS; } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT_熊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值