代码之家  ›  专栏  ›  技术社区  ›  Alex Itelman

以编程方式获取iOS应用程序中的内存使用实时/脏字节(非常驻/实字节)

  •  8
  • Alex Itelman  · 技术社区  · 7 年前

    根据我到目前为止读到的内容,real/resident bytes表示分配给应用程序的字节数,包括应用程序不再使用但尚未被操作系统回收的字节数。 live/dirty bytes是应用程序实际使用的字节,操作系统无法回收。 我认为XCode调试导航器中显示的数字是活动字节。

    我对通过编程获得这个数字很感兴趣(用于我们自己的统计/分析),但我发现的代码只能给出常驻字节的值,这大于Xcode在某些设备上显示的值(几乎是两倍大),实际上是在相同的设备上,但不同的iOS版本上。(在iOS 9上,它给出的值几乎是两倍大,但在iOS 11上,它给出的值几乎与Xcode相同)。

    我使用的代码如下:

    struct mach_task_basic_info info;
    mach_msg_type_number_t size = MACH_TASK_BASIC_INFO_COUNT;
    kern_return_t kerr = task_info(mach_task_self(),
                                   MACH_TASK_BASIC_INFO,
                                   (task_info_t)&info,
                                   &size);
    if( kerr == KERN_SUCCESS ) {
        NSLog(@"Memory in use (in bytes): %u", info.resident_size);
        return info.resident_size;
    } else {
        NSLog(@"Error with task_info(): %s", mach_error_string(kerr));
    }
    

    是否有一些代码可以像Xcode显示的那样获取live bytes值?

    2 回复  |  直到 7 年前
        1
  •  9
  •   Alex Itelman    7 年前

    我发现了一些其他的东西,但似乎在设备上使用之前的方法不起作用,而在设备上使用之前的方法不起作用:-( 现在我需要弄清楚如何知道使用哪一个。一款是配备iOS 9的iPhone 5s,另一款是配备iOS 11的iPhone 5s。 我想我需要在更多的设备上测试。。。

    我在这里找到的:

    https://opensource.apple.com/source/WebKit/WebKit-7603.1.30.1.33/ios/Misc/MemoryMeasure.mm.auto.html

    这在Objective-C中转化为如下内容:

    task_vm_info_data_t vmInfo;
    mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
    kern_return_t err = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count);
    if (err != KERN_SUCCESS)
        return 0;
    
    NSLog(@"Memory in use vmInfo.internal (in bytes): %u", vmInfo.internal);
    
    return vmInfo.internal;
    

    我想如果我添加vmInfo。内部和vmInfo。压缩后,我将得到正确的结果(匹配Xcode调试导航器显示的内容)

    到目前为止,这两台设备以及我测试的另外两台设备看起来都很合适。

    因此,我的最终代码如下所示:

    task_vm_info_data_t info;
    mach_msg_type_number_t size = TASK_VM_INFO_COUNT;
    kern_return_t kerr = task_info(mach_task_self(),
                                   TASK_VM_INFO,
                                   (task_info_t)&info,
                                   &size);
    if( kerr == KERN_SUCCESS ) {
        mach_vm_size_t totalSize = info.internal + info.compressed;
        NSLog(@"Memory in use (in bytes): %u", totalSize);
        return totalSize;
    } else {
        NSLog(@"Error with task_info(): %s", mach_error_string(kerr));
    }
    
        2
  •  5
  •   Arkadii    5 年前

    由于在Obj-C和Swift中对达尔文类型的访问看起来略有不同,我想添加我在Swift中提出的基于 Alex's answer :

    let TASK_VM_INFO_COUNT = MemoryLayout<task_vm_info_data_t>.size / MemoryLayout<natural_t>.size
    
    var vmInfo = task_vm_info_data_t()
    var vmInfoSize = mach_msg_type_number_t(TASK_VM_INFO_COUNT)
    
    let kern: kern_return_t = withUnsafeMutablePointer(to: &vmInfo) {
            $0.withMemoryRebound(to: integer_t.self, capacity: 1) {
                task_info(mach_task_self_,
                          task_flavor_t(TASK_VM_INFO),
                          $0,
                          &vmInfoSize)
                }
            }
    
    if kern == KERN_SUCCESS {
        let usedSize = DataSize(bytes: Int(vmInfo.internal + vmInfo.compressed))
        print("Memory in use (in bytes): %u", usedSize)
    } else {
        let errorString = String(cString: mach_error_string(kern), encoding: .ascii) ?? "unknown error"
        print("Error with task_info(): %s", errorString);
    }
    

    此代码基于类似 answer 具有 mach_task_basic_info resident_size .