dumpsys meminfo执行流程(二)

本文详细解析了dumpsys meminfo命令如何通过JNI从native层获取kernel的内存数据,介绍了getMemoryInfo()和getMemInfo()函数的具体过程,包括JNI函数签名和参数描述符的规则,以及native如何将数据写入Java变量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一节介绍了dumpsys meminfo命令执行的大致流程,这一节要讲的是dumpsys meminfo如何从native层拿到原始的memory系统数据以及dumpsys meminfo各数据的组成。


我们知道Java要与native之间进行相互调用,必须通过JNI层,在dumpsys meminfo执行过程中需要从native拿到从kernel传上来的系统memory的相关数据,这就需要通过JNI层。

具体过程如下:

首先是两个从native拿数据,位于debug.java中的函数:

public static native void getMemoryInfo(MemoryInfo memoryInfo);

public static native void getMemInfo(long[] outSizes);

先看getMemoryInfo()函数,此函数是调用的native的函数,经过jni转化:

{ "getMemoryInfo",          "(ILandroid/os/Debug$MemoryInfo;)V",
            (void*) android_os_Debug_getDirtyPagesPid },

调用native的函数android_os_Debug_getDirtyPagesPid():

static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
        jint pid, jobject object)//更新Java层pss相关的信息
{
    bool foundSwapPss = false;
    stats_t stats[_NUM_HEAP];
    memset(&stats, 0, sizeof(stats));

    load_maps(pid, stats, &foundSwapPss);//对当前进程的smaps的信息进行统计,统计完成之后放到stats[]数组中

    struct graphics_memory_pss graphics_mem;
    if (read_memtrack_memory(pid, &graphics_mem) == 0) {//获取graphic的memory消耗数据,graphic所占用的数据必须单独统计
        stats[HEAP_GRAPHICS].pss = graphics_mem.graphics;
        stats[HEAP_GRAPHICS].privateDirty = graphics_mem.graphics;
        stats[HEAP_GL].pss = graphics_mem.gl;
        stats[HEAP_GL].privateDirty = graphics_mem.gl;
        stats[HEAP_OTHER_MEMTRACK].pss = graphics_mem.other;
        stats[HEAP_OTHER_MEMTRACK].privateDirty = graphics_mem.other;
    }

    for (int i=_NUM_CORE_HEAP; i<_NUM_EXCLUSIVE_HEAP; i++) {//将除native和dalvik所占用的内存除外的内存占用类型全部划为other_***
        stats[HEAP_UNKNOWN].pss += stats[i].pss;
        stats[HEAP_UNKNOWN].swappablePss += stats[i].swappablePss;
        stats[HEAP_UNKNOWN].privateDirty += stats[i].privateDirty;
        stats[HEAP_UNKNOWN].sharedDirty += stats[i].sharedDirty;
        stats[HEAP_UNKNOWN].privateClean += stats[i].privateClean;
        stats[HEAP_UNKNOWN].sharedClean += stats[i].sharedClean;
        stats[HEAP_UNKNOWN].swappedOut += stats[i].swappedOut;
        stats[HEAP_UNKNOWN].swappedOutPss += stats[i].swappedOutPss;
    }

    for (int i=0; i<_NUM_CORE_HEAP; i++) {//将other_**, native_***和dalvik_***全部放到java层的meminfo类中对应的变量中,具体如何操作将在后面讲到
        env->SetIntField(object, stat_fields[i].pss_field, stats[i].pss);
        env->SetIntField(object, stat_fields[i].pssSwappable_field, stats[i].swappablePss);
        env->SetIntField(object, stat_fields[i].privateDirty_field, stats[i].privateDirty);
       env->SetIntField(object, stat_fields[i].sharedDirty_field, stats[i].sharedDirty);
        env->SetIntField(object, stat_fields[i].privateClean_field, stats[i].privateClean);
        env->SetIntField(object, stat_fields[i].sharedClean_field, stats[i].sharedClean);
        env->SetIntField(object, stat_fields[i].swappedOut_field, stats[i].swappedOut);
        env->SetIntField(object, stat_fields[i].swappedOutPss_field, stats[i].swappedOutPss);
    }


    env->SetBooleanField(object, hasSwappedOutPss_field, foundSwapPss == false ? JNI_FALSE : JNI_TRUE);
    jintArray otherIntArray = (jintArray)env->GetObjectField(object, otherStats_field);

    jint* otherArray = (jint*)env->GetPrimitiveArrayCritical(otherIntArray, 0);
    if (otherArray == NULL) {
        return;
    }

    int j=0;
    for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {//将之前统计在other_***类型内存中的数据进行整理,存放在Java的meminfo类的otherstat[]数组当中
        otherArray[j++] = stats[i].pss;
        otherArray[j++] = stats[i].swappablePss;
        otherArray[j++] = stats[i].privateDirty;
        otherArray[j++] = stats[i].sharedDirty;
        otherArray[j++] = stats[i].privateClean;
        otherArray[j++] = stats[i].sharedClean;
        otherArray[j++] = stats[i].swappedOut;
        otherArray[j++] = stats[i].swappedOutPss;
    }

    env->ReleasePrimitiveArrayCritical(otherIntArray, otherArray, 0);
}

android_os_Debug_getDirtyPagesPid()调用的是load_maps()函数:

static void load_maps(int pid, stats_t* stats, bool* foundSwapPss)
{
    char tmp[128];
    FILE *fp;

    sprintf(tmp, "/proc/%d/smaps", pid);
    fp = fopen(tmp, "r");//打开proc/<pid>/smaps文件
    if (fp == 0) return;

    read_mapinfo(fp, stats, foundSwapPss);//解析smaps文件
    fclose(fp);
}
接着调用的是read_mapinfo():

static void read_mapinfo(FILE *fp, stats_t* stats, bool* foundSwapPss)
{
    char line[1024];
    int len, nameLen;
    bool skip, done = false;

    unsigned pss = 0, swappable_pss = 0;
    float sharing_proportion = 0.0;
    unsigned shared_clean = 0, shared_dirty = 0;
    unsigned private_clean = 0, private_dirty = 0;
    unsigned swapped_out = 0, swapped_out_pss = 0;
    bool is_swappable = false;
    unsigned temp;

    uint64_t start;
    uint64_t end = 0;
    uint64_t prevEnd = 0;
    char* name;
    int name_pos;

    int whichHeap = HEAP_UNKNOWN;
    int subHeap = HEAP_UNKNOWN;
    int prevHeap = HEAP_UNKNOWN;

    *foundSwapPss = false;

    if(fgets(line, sizeof(line), fp) == 0) return;

    while (!done) {//循环解析smaps每一行的内容,将这些所占用的内存进行分类,然后将所得到的各类的内存值再根据不同的pss进行累加,最后的结果存放在stats[]数组里面
        prevHeap = whichHeap;
        prevEnd = end;
        whichHeap = HEAP_UNKNOWN;
        subHeap = HEAP_UNKNOWN;
        skip = false;
        is_swappable = false;

        len = strlen(line);
        if (len < 1) return;
        line[--len] = 0;
       if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) {
            skip = true;
        } else {
            while (isspace(line[name_pos])) {
                name_pos += 1;
            }
 
对于Android系统UI性能的自动化测试,我们可以利用LogCat、dumpsys meminfo以及Google Trace (GT)等工具,结合MonkeyRunner实现自动化的测试流程。以下是一个详细的测试流程和工具使用方法: 参考资源链接:[自动化测试Android UI性能:启动时间、流畅度与内存优化](https://wenku.youkuaiyun.com/doc/6j4mmarriz?spm=1055.2569.3001.10343) 首先,我们需要确定UI性能的关键测试指标,包括启动时延、流畅度和内存使用情况。为了测试启动时延,可以通过LogCat工具来监控应用的启动日志。在LogCat中设置过滤器,以便捕获与应用启动相关的日志信息,然后使用脚本解析这些日志,获取精确的启动耗时。这个过程可以自动化执行,并且可以通过设置阈值来判定启动时间是否符合预期。 接下来,为了测试内存使用情况,可以使用dumpsys meminfo命令。此命令能够提供当前系统或特定进程的内存使用信息。通过定时执行dumpsys meminfo命令,并分析内存使用数据的变化趋势,我们可以评估应用的内存管理是否有效。此外,Android Studio中的Heap视图也能够提供内存分配的可视化信息,这有助于识别内存泄漏等问题。 对于UI流畅度的测试,可以借助Google Trace (GT)工具。GT工具能够记录设备上发生的事件,并通过分析这些事件来评估应用的性能,特别是流畅度。通过执行特定的操作序列,并利用GT工具进行记录,我们可以得到一个关于UI流畅度的详细报告。 如果需要进行更复杂的交互测试,可以使用MonkeyRunner工具。它允许我们编写Python脚本来模拟用户操作,例如滑动和点击,同时可以实时获取帧率(FPS)来评估UI的流畅度。将MonkeyRunner脚本与上述工具结合,可以构建一个全面的自动化测试环境。 最后,为了提高测试效率,可以将以上工具集成到一个自动化测试框架中,通过持续集成(CI)平台进行自动化测试的调度和结果的分析。例如,可以使用Jenkins这样的CI工具,设置定时任务来执行自动化脚本,并通过Email、短信等方式及时通知测试结果。 综上所述,通过掌握Android系统内建的测试工具和合理地使用自动化测试框架,我们可以有效地对Android应用的UI性能进行评估,提高测试的效率和准确性。详细的操作方法和策略,可以参考《自动化测试Android UI性能:启动时间、流畅度与内存优化》这份资料,其中不仅提供了理论分析,还提供了实际操作的解决方案,对于Android UI性能测试具有重要的指导作用。 参考资源链接:[自动化测试Android UI性能:启动时间、流畅度与内存优化](https://wenku.youkuaiyun.com/doc/6j4mmarriz?spm=1055.2569.3001.10343)
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值